TweetFollow Us on Twitter

Mar 98 - Getting Started

Volume Number: 14 (1998)
Issue Number: 3
Column Tag: Getting Started

On the Menu for Today...

by Dave Mark

How the Macintosh Menu Manager Works

In last month's column, we expanded our event-handling repertoire to include activate, update, and suspend/resume events. By now, you should feel pretty comfortable with the Event Manager. If you haven't already, put down this column and go read the Event Manager chapters in Inside Macintosh: Macintosh Toolbox Essentials.

In this month's column, we're going to take a look at the Menu Manager, the part of the Toolbox responsible for your program's menus.

The Pull-Down Menu

Almost every single Macintosh program comes complete with its own menu bar, the strip of menu titles along the top of your Mac's main screen. The menu bar contains one menu title for each of your program's current pull-down menus. Figure 1 shows the Finder's menu bar with the File menu pulled down.

Figure 1. A menu bar with a pull-down menu exposed.

A proper menu bar always features at least three menus, Apple, File, and Edit. When a menu is pulled-down, its menu items will be drawn. In addition to the item's name, a menu item may feature an icon, as well as a command-key equivalent. The command-key equivalent, when typed by the user, simulates the selection of the equivalenced menu item. For example, in the menu in Figure 1, the command-key equivalent cmd-W will cause the Close Window item to be selected from the File menu.

Items may be dimmed, or disabled, which prevents the user from selecting them. If an item is disabled, it is drawn in gray. A normal item is said to be enabled.

You may have noticed that some menu items are drawn followed by an ellipsis, a sequence of three dots (...). The ellipsis tells the user that this item will cause a dialog box to appear, prompting the user for further information. We'll get to dialog boxes in a later column.

Working With the Menu Manager

The Menu Manager consists of a series of routines designed to work with two resource types, MBAR and MENU. The MBAR resource links together a series of MENU resources to form a menu bar. A MENU resource is used to completely specify a menu, including all the menus items and any associated icons and command-key equivalents. Here's a quick tour through the main Menu Manager routines.

Once you've built your MBAR and MENU resources (you'll see how in a bit), you're ready to start programming. You'll start off by creating a menu initialization routine. In it, you'll call GetNewMBar(), which builds a menu list, based on the MENUs specified in an MBAR resource. A menu list is the data structure the Menu Manager bases a menu bar on. Once the menu list is built, pass it to SetMenuBar() to make it the current menu bar. Note that you can have more than one menu bar, but only one current menu bar.

Once you've specified a current menu bar, draw the menu bar by calling DrawMenuBar(). Now you're ready to work with your individual menus.

Modifying the Menu Bar

There will be times when the menu bar described in your MBAR resource won't be enough. For example, you might have a menu that appears only if the user has color turned on, or when a certain type of window is open. You can add a menu to or delete a menu from the menu bar. To add a menu to the menu bar, call GetMenu() to load a new MENU resource into memory, into the list of available menus (but not into the current menu bar). GetMenu() returns a MenuHandle which you can pass to InsertMenu(). InsertMenu() inserts the specified menu into the current menu bar. To delete a menu from the menu bar, call DeleteMenu().

Another routine you might find useful is GetMenuHandle(), which returns a MenuHandle to a menu already loaded into memory. Basically, you'll use GetMenu() to get a handle to a menu that's never been loaded, and GetMenuHandle() to get a handle to a previously loaded menu. Use InsertMenu() to add a loaded menu into the current menu bar. Remember, whenever you change the menu bar, call DrawMenuBar() to bring your changes to life. You only need to call DrawMenuBar() when you change the current menu bar, not when you change a menu's items.

Changing a Menu Item's Appearance

The Menu Manager gives you a set of routines you can use to customize your menus. For example, the routines EnableItem() and DisableItem() allow you to enable or disable a menu item. You can use the routine AppendResMenu() to add all the resources of a specific type as menu items. There are two specific times when this comes in handy. To add all the fonts to a menu, pass 'FONT' to AppendResMenu(). To add all the standard apple menu items to the apple menu, pass 'DRVR' to AppendResMenu(). Why 'DRVR'? Prior to System 7, all the items in the apple menu were desk accessories, which have a resource type of 'DRVR'. Even though System 7 allows you to add more than DA's to your apple menu, AppendResMenu() still works properly, as you'll see by this month's program.

You can use SetMenuItemText() to change the name of a menu item. You can use GetMenuItemText() to retrieve an item's name. CheckItem() lets you place or remove a check mark from an item and SetItemMark() lets you place or remove any character from the system font next to an item. GetItemMark() retrieves an item's mark.

SetItemIcon() and GetItemIcon() set and get the resource ID of any icon associated with an item. For some reason, the resource ID returned by GetItemIcon() is 256 less than the icon's actual resource ID. This means that your icon's resource ID will range from 257 to 511.

SetItemStyle() and GetItemStyle() are used to set and get the style of an item's name. We'll make use of these function's in next month's program.

Detecting a Menu Selection

There are two ways a user can select from a menu. They can click the mouse in the menu bar or they can type a command-key equivalent. You'll detect a mouse click in the menu bar by detecting a mouseDown event that occurred inMenuBar. If this happens, you'll call a routine called MenuSelect(). MenuSelect() tracks your mouse, pulling down menus, highlighting items, and, if necessary, selecting an item from a menu. MenuSelect() returns a value that indicates the menu and item that was selected.

If a keyDown or autoKey event occurs, you'll check to see if the command-key was down when the event occurred. If so, you'll call a routine called MenuKey() which translates the key to a value that indicates the menu and item that was selected.

Whether the menu/item was selected via a keyDown or a mouseDown in the menu bar, it will be translated into a menu/item value. You'll pass this menu/item value on to your own routine which processes the menu selection. Once you process the menu selection, call HiliteMenu() to uninvert the menu's title, which was left inverted by MenuSelect() or MenuKey().

MenuMaster

OK, that's about it for Menu Manager routines. There are a few that we haven't discussed and you should definitely read the Menu Manager chapter in Inside Macintosh: Macintosh Toolbox Essentials. For now, let's get into this month's program, MenuMaster.

Create a folder named MenuMaster in your development folder. Now, go into ResEdit and create a new resource file named MenuMaster.rsrc in the MenuMaster folder. Select Create New Resource from the Resource menu and create a new MBAR resource. When the MBAR window appears, click the row of *'s (Figure 2) and type cmd-K to create a new MENU field. When the new field appears, type in the MENU id 128.

Figure 2. Click the *'s and type cmd-K to add a MENU to the MBAR.

When the second row of *'s appears, click it and type cmd-K to create a second MENU field. Repeat this process till your MBAR looks like the one in Figure 3.

Close the MBAR window, and close the MBAR picker window. Next, select Create New Resource from the Resource menu and create a MENU resource. When the MENU editing window appears, click the Apple radio button to create an Apple menu. Hit a carriage return and type in the text About MenuMaster... followed by another carriage return. Now click the separator-line radio button to insert a separator line after the About MenuMaster... item. Because separator lines are never enabled, they'll never be chosen by the user. Your menu should look like the one shown in

Figure 4

.

Figure 3. The filled out MBAR resource with four MENU resource ids.

Figure 4. Specifications for MENU 128.

Close the editing window and press cmd-K to create a new MENU resource. This time, instead of clicking the Apple radio button, type the word File in the Title field and hit a carriage return. Next type the word Quit and type the letter Q in the Cmd-Key field that appears. You've just made cmd-Q a command-key equivalent to the File menu's Quit item. Your menu should look like the one shown in Figure 5.

Figure 5. Specifications for MENU 129.

Close the editing window and create another MENU, using the MENU shown in Figure 6 as a guide. Be sure to add the separator line after the Undo item, and to type in the four command-key equivalents.

Figure 6. Specifications for MENU 130.

Close the editing window and create yet another MENU, according to the specifications shown in Figure 7. Be sure to include the three separator lines. If you forget one, you can add one at the end of the menu, then click and drag it to its proper position. Notice that the item labeled Enable Previous Item has been disabled. Do this by making sure the Enabled check box is unchecked for that item only.

Figure 7. Specifications for MENU 131.

Finally, create one more MENU. Use the title Extra Menu and add the item Delete This Menu (Figure 8).

Figure 8. Specifications for MENU 132.

Next, click the item Delete This Menu and select Choose Icon... from the MENU menu. You're going to attach an icon to the menu item. When the dialog box appears, click the Small Icons radio button, then click the New button.

Figure 9. The Choose Icon... dialog box.

When the SICN editing window appears, go to town. Create whatever kind of small icon your heart desires. Get creative. Figure 10 shows my SICN, lifted from the Macintosh Programming Primer.

Figure 10. A SICN with a resource ID of 257.

If you preferred, you could use an ICON or a reduced ICON resource instead. Personally, I prefer SICNs or none at all. Once you are done editing your SICN, close the SICN editing window. You can get a preview of the menu by clicking the prototype that appears on the right end of the menu bar. Your SICN should be in place. If not, be sure your SICN has a resource ID of 257. Icons attached to menu items must have an ID between 257 and 511.

Once you are happy with your MENU, close the MENU editing window. You may have noticed that you've created MENUs with resource IDs 128 through 132, while your MBAR only includes MENUs with IDs from 128 to 131. We'll add this extra menu to our menu bar from inside our program.

Well, that's about it for resources. Quit ResEdit, making sure you Save your changes.

Creating the MenuMaster Project

Launch CodeWarrior and create a new project based on the MacOS:C/C++:Basic Toolbox 68k stationary. Turn off the Create Folder check box. Name the project MenuMaster.mcp and place it in your MenuMaster folder. Remove SillyBalls.c and SillyBalls.rsrc from the project; we will not be using these files. From the Finder, drag and drop your MenuMaster.rsrc file into the project window. You also can remove the ANSI Libraries group from the project, because we won't need them, either.

Select New from the File menu to create a new window. Save it under the name MenuMaster.c, Select Add Window from the Project menu to add MenuMaster.c to the project. Your project window should look something like Figure 11.

Figure 11. MenuMaster project window.

Rather than print the code here twice, we'll go straight to the walk-through. You can type in the code as we discuss it below and you will end up with the complete program, or you can save your fingures some effort and get the complete project from MacTech's ftp site ftp://ftp.mactech.com/src/.

Walking Through the Source Code

Much of MenuMaster's code should be familiar to you. That being the case, I'm going to breeze over the familiar stuff, focusing on the new stuff.

For starters, notice the way the #defines have been set up for the menus and menu items. In general, you'll create a #define for each menu and item, starting the menu #defines with the letter 'm' and the item #defines with the letter 'i'.

#include <Menus.h>
#include <Sound.h>

#define kBaseResID    128
#define kMoveToFront  (WindowPtr)-1L
#define kSleep        7

#define kLastMenu      0

#define mApple        kBaseResID
#define iAbout        1

#define mFile          kBaseResID+1
#define iQuit          1

#define mOptions      kBaseResID+3
#define iChangeName    1
#define iDisableMe    3
#define iEnablePrev    4
#define iAddExtraMenu  6
#define iAppendItem    8
#define iAddedItem    9

#define kUnchangedName    "\pChange My Name"
#define kChangedName    "\pChange Me Back Again"

#define mExtraMenu    kBaseResID+4
#define iDeleteMenu    1

The global gItemNameChanged is a Boolean flag, used to tell whether the first Options item has been changed or not.

Boolean    gDone;
Boolean    gItemNameChanged = false;

And we can't forget our function declarations:

void  ToolBoxInit( void );
void  WindowInit( void );
void  MenuBarInit( void );
void  EventLoop( void );
void  DoEvent( EventRecord *eventPtr );
void  HandleMouseDown( EventRecord *eventPtr );
void  HandleMenuChoice( long menuChoice );
void  HandleAppleChoice( short item );
void  HandleFileChoice( short item );
void  HandleOptionsChoice( short item );
void  HandleExtraMenuChoice( short item );

Notice that main() calls a new routine, MenuBarInit(), which handles the menu initialization. ToolboxInit() hasn't changed.

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

void  main( void )
{
  ToolBoxInit();
  MenuBarInit();
  
  EventLoop();
}

/*************************** ToolBoxInit */

void  ToolBoxInit( void )
{
  InitGraf( &qd.thePort );
  InitFonts();
  InitWindows();
  InitMenus();
  TEInit();
  InitDialogs( nil );
  InitCursor();
}

MenuBarInit() loads the MBAR resource and makes the resulting menu bar the current menu bar.

/****************** MenuBarInit **********/

void  MenuBarInit( void )
{
  Handle        menuBar;
  MenuHandle    menu;
  
  menuBar = GetNewMBar( kBaseResID );
  SetMenuBar( menuBar );

Next, AppendResMenu() is called to add the apple menu items to the Apple menu. Notice that GetMenuHandle() was used to retrieve the menu handle, because the MENU resource was already loaded into memory as part of the MBAR.

  menu = GetMenuHandle( mApple );
  AppendResMenu( menu, 'DRVR' );

Finally, the menu bar is drawn with DrawMenuBar().

  DrawMenuBar();
}

We have our standard EventLoop().

/************************* EventLoop *********/

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

The next big change is in the DoEvent() code.

/************************* DoEvent   */

void  DoEvent( EventRecord *eventPtr )
{
  char    theChar;
  
  switch ( eventPtr->what )
  {
    case mouseDown: 
      HandleMouseDown( eventPtr );
      break;

The charCodeMask is used to retrieve the character embedded in the keyDown or autoKey event. If the command-key was held down, the character is passed to MenuKey() which translates it into a menu and item code. This code is passed on to HandleMenuChoice().

    case keyDown:
    case autoKey:
      theChar = eventPtr->message & charCodeMask;
      if ( (eventPtr->modifiers & cmdKey) != 0 ) 
        HandleMenuChoice( MenuKey( theChar ) );
      break;
  }
}

HandleMouseDown() also contains a change.

/************************ HandleMouseDown */

void  HandleMouseDown( EventRecord *eventPtr )
{
  WindowPtr    window;
  short        thePart;
  long          menuChoice;
  
  thePart = FindWindow( eventPtr->where, &window );
  
  switch ( thePart )
  {

If the mouseDown was in the menu bar, the event is passed on to MenuSelect() which also returns a menu and item code. The code is again passed on to HandleMenuChoice().

    case inMenuBar:
      menuChoice = MenuSelect( eventPtr->where );
      HandleMenuChoice( menuChoice );
      break;
    case inSysWindow : 
      SystemClick( eventPtr, window );
      break;
  }
}

HandleMenuChoice() pulls the menu and item out of the menu/item code.

/****************** HandleMenuChoice **************/

void  HandleMenuChoice( long menuChoice )
{
  short    menu;
  short    item;
  
  if ( menuChoice != 0 )
  {
    menu = HiWord( menuChoice );
    item = LoWord( menuChoice );

menu is used to decide which menu handling routine to call.

    switch ( menu )
    {
      case mApple:
        HandleAppleChoice( item );
        break;
      case mFile:
        HandleFileChoice( item );
        break;
      case mOptions:
        HandleOptionsChoice( item );
        break;
      case mExtraMenu:
        HandleExtraMenuChoice( item );
        break;
    }

Once the handling routine returns, HiliteMenu() is called to unhighlight the selected menu.

    HiliteMenu( 0 );
  }
}

/****************** HandleAppleChoice *************/

void  HandleAppleChoice( short item )
{
  MenuHandle  appleMenu;
  Str255      accName;
  short      accNumber;
  
  switch ( item )
  {

HandleAppleChoice() handles the About MenuMaster... item by beeping once.

    case iAbout:
      SysBeep( 20 );
      break;

If any other item is selected, OpenDeskAcc() is called to launch the appropriate item. Under System 7, the item might not be a desk accessory.

    default:
      appleMenu = GetMenuHandle( mApple );
      GetMenuItemText( appleMenu, item, accName );
      accNumber = OpenDeskAcc( accName );
      break;
  }
}

HandleFileChoice() sets gDone to true, which will cause the program to exit.

/****************** HandleFileChoice ***********/

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

HandleOptionsChoice() takes the appropriate action, depending on the action selected. Notice that GetMenuHandle() is used to retrieve the Options menu handle.

/****************** HandleOptionsChoice **********/

void  HandleOptionsChoice( short item )
{
  MenuHandle  menu;
  
  menu = GetMenuHandle( mOptions );
  
  switch ( item )
  {
    case iChangeName:
      if ( gItemNameChanged )
        SetMenuItemText( menu, iChangeName, kUnchangedName );
      else
        SetMenuItemText( menu, iChangeName, kChangedName );
      gItemNameChanged = ! gItemNameChanged;
      break;
    case iDisableMe:
      DisableItem( menu, iDisableMe );
      EnableItem( menu, iEnablePrev );
      break;
    case iEnablePrev:
      DisableItem( menu, iEnablePrev );
      EnableItem( menu, iDisableMe );
      break;
    case iAddExtraMenu:
      DisableItem( menu, iAddExtraMenu );
      menu = GetMenu( mExtraMenu );
      InsertMenu( menu, kLastMenu );
      DrawMenuBar();
      break;
    case iAppendItem:
      AppendMenu( menu, "\pCan't Delete Me..." );
      DisableItem( menu, iAppendItem );
      break;
    case iAddedItem:
      SysBeep( 20 );
      break;
  }
}

Finally, HandleExtraMenuChoice() handles a single item.

/****************** HandleExtraMenuChoice ********/

void  HandleExtraMenuChoice( short item )
{
  MenuHandle  menu;
  
  switch ( item )
  {

When Delete This Menu is selected, the Add Extra Menu item is reenabled on the Options menu.

    case iDeleteMenu:
      menu = GetMenuHandle( mOptions );
      EnableItem( menu, iAddExtraMenu );

Next, the Extra Menu menu is deleted and the menu bar is redrawn.

      DeleteMenu( mExtraMenu );
      DrawMenuBar();
      break;
  }
}

That's it. Be sure to save the file if you are typing this in.

Running MenuMaster

Run the project by selecting Run from the Project menu. When the menu bar appears, select Change My Name from the Options menu. If you click on the Options menu again, you'll see that the item has been changed to Change Me Back Again. Select the item again and it will change back to its original name.

Now select Disable Me from the Options menu. If you click on the Options menu again, you'll see that the item has been disabled and the next item, which was disabled, is now enabled. Select Enable Previous Item and it will be disabled again, while the Disable Me item is reenabled.

Next, select Add Extra Menu from the Options menu. A new menu will appear in the menu bar, named Extra Menu. In addition, the Add Extra Menu item is disabled. If you click Extra Menu, you'll notice that the SICN appears to the left of the Delete This Menu item. Select Delete This Menu and the menu will disappear, and Add Extra Menu will be reenabled.

Next, select Append Item from the Options menu. A new item will appear in the Options menu with the name Can't Delete Me.... As its name implies, once you've added an item to a menu, you can't delete it. If you select Can't Delete Me..., MenuMaster will beep once.

Finally, type cmd-Q to exit the program. cmd-Q is the command-key equivalent for the File menu's Quit item.

Till Next Time

Well, that's about it for this month. Next month, we'll dig a little further into the Menu Manager. Till then, go read Inside Macintosh, and save me a slice of pizza...

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Daylite 6.7.3 - Dynamic business organiz...
Daylite helps businesses organize themselves with tools such as shared calendars, contacts, tasks, projects, notes, and more. Enable easy collaboration with features such as task and project... Read more
VirtualBox 6.0.10 - x86 virtualization s...
VirtualBox is a family of powerful x86 virtualization products for enterprise as well as home use. Not only is VirtualBox an extremely feature rich, high performance product for enterprise customers... Read more
BetterTouchTool 3.149 - Customize multi-...
BetterTouchTool adds many new, fully customizable gestures to the Magic Mouse, Multi-Touch MacBook trackpad, and Magic Trackpad. These gestures are customizable: Magic Mouse: Pinch in / out (zoom)... Read more
Dropbox 77.4.131 - Cloud backup and sync...
Dropbox is an application that creates a special Finder folder that automatically syncs online and between your computers. It allows you to both backup files and keeps them up-to-date between systems... Read more
MainStage 3 3.4.3 - Live performance too...
Apple MainStage makes it easy to bring to the stage all the same instruments and effects that you love in your recording. Everything from the Sound Library and Smart Controls you're familiar with... Read more
Paperless 3.0.6 - $69.95
Paperless is a digital documents manager. Remember when everyone talked about how we would soon be a paperless society? Now it seems like we use paper more than ever. Let's face it - we need and we... Read more
TextMate 2.0.rc.29 - Code/markup editor...
TextMate is a versatile plain text editor with a unique and innovative feature set which caused it to win an Apple Design Award for Best Mac OS X Developer Tool in August 2006 A rapidly growing... Read more
Notability 4.0.4 - Note-taking and annot...
Notability is a powerful note-taker to annotate documents, sketch ideas, record lectures, take notes and more. It combines, typing, handwriting, audio recording, and photos so you can create notes... Read more
CleanMyMac X 4.4.4 - Delete files that w...
CleanMyMac makes space for the things you love. Sporting a range of ingenious new features, CleanMyMac lets you safely and intelligently scan and clean your entire system, delete large, unused files... Read more
Geekbench 4.4.0 - Measure processor and...
Geekbench provides a comprehensive set of benchmarks engineered to quickly and accurately measure processor and memory performance. Designed to make benchmarks easy to run and easy to understand,... Read more

Latest Forum Discussions

See All

TEPPEN guide - Tips and tricks for new p...
TEPPEN is a wild game that nobody asked for, but I’m sure glad it exists. Who would’ve thought that a CCG featuring Capcom characters could be so cool and weird? In case you’re not completely sure what TEPPEN is, make sure to check out our review... | Read more »
Dr. Mario World guide - Other games that...
We now live in a post-Dr. Mario World world, and I gotta say, things don’t feel too different. Nintendo continues to squirt out bad games on phones, causing all but the most stalwart fans of mobile games to question why they even bother... | Read more »
Strategy RPG Brown Dust introduces its b...
Epic turn-based RPG Brown Dust is set to turn 500 days old next week, and to celebrate, Neowiz has just unveiled its biggest and most exciting update yet, offering a host of new rewards, increased gacha rates, and a brand new feature that will... | Read more »
Dr. Mario World is yet another disappoin...
As soon as I booted up Dr. Mario World, I knew I wasn’t going to have fun with it. Nintendo’s record on phones thus far has been pretty spotty, with things trending downward as of late. [Read more] | Read more »
Retro Space Shooter P.3 is now available...
Shoot-em-ups tend to be a dime a dozen on the App Store, but every so often you come across one gem that aims to shake up the genre in a unique way. Developer Devjgame’s P.3 is the latest game seeking to do so this, working as a love letter to the... | Read more »
Void Tyrant guide - Guildins guide
I’ve still been putting a lot of time into Void Tyrant since it officially released last week, and it’s surprising how much stuff there is to uncover in such a simple-looking game. Just toray, I finished spending my Guildins on all available... | Read more »
Tactical RPG Brown Dust celebrates the s...
Neowiz is set to celebrate the summer by launching a 2-month long festival in its smash-hit RPG Brown Dust. The event kicks off today, and it’s divided into 4 parts, each of which will last two weeks. Brown Dust is all about collecting, upgrading,... | Read more »
Flappy Royale is an incredibly clever ta...
I spent the better part of my weekend playing Flappy Royale. I didn’t necessarily want to. I just felt like I had to. It’s a hypnotic experience that’s way too easy to just keep playing. | Read more »
Void Tyrant guide - General tips and tri...
Void Tyrant is a card-based dungeon-crawler that doesn’t fit in the mold of other games in the genre. Between the Blackjack-style combat and strange gear system alone, you’re left to your own devices to figure out how best to use everything to your... | Read more »
Webzen’s latest RPG First Hero is offici...
You might be busy sending your hulking Dark Knight into the midst of battle in Webzen’s other recent release: the long-anticipated MU Origin 2. But for something a little different, the South Korean publisher has launched First Hero. Released today... | Read more »

Price Scanner via MacPrices.net

Amazon drops prices, now offers clearance 13″...
Amazon has new dropped prices on clearance 13″ 2.3GHz Dual-Core non-Touch Bar MacBook Pros by $200 off Apple’s original MSRP, with prices now available starting at $1099. Shipping is free. Be sure to... Read more
2018 15″ MacBook Pros now on sale for $500 of...
Amazon has dropped prices on select clearance 2018 15″ 6-Core MacBook Pros to $500 off Apple’s original MSRP. Prices now start at $1899 shipped: – 2018 15″ 2.2GHz Touch Bar MacBook Pro Silver: $1899.... Read more
Price drop! Clearance 12″ 1.2GHz Silver MacBo...
Amazon has dropped their price on the recently-discontinued 12″ 1.2GHz Silver MacBook to $849.99 shipped. That’s $450 off Apple’s original MSRP for this model, and it’s the cheapest price available... Read more
Apple’s 21″ 3.0GHz 4K iMac drops to only $936...
Abt Electronics has dropped their price on clearance, previous-generation 21″ 3.0GHz 4K iMacs to only $936 shipped. That’s $363 off Apple’s original MSRP, and it’s the cheapest price we’ve seen so... Read more
Amazon’s Prime Day savings on Apple 11″ iPad...
Amazon has new 2018 Apple 11″ iPad Pros in stock today and on sale for up to $250 off Apple’s MSRP as part of their Prime Day sale (but Prime membership is NOT required for these savings). These are... Read more
Prime Day Apple iPhone deal: $100 off all iPh...
Boost Mobile is offering Apple’s new 2018 iPhone Xr, iPhone Xs, and Xs Max for $100 off MSRP. Their discount reduces the cost of an Xs to $899 for the 64GB models and $999 for the 64GB Xs Max. Price... Read more
Clearance 13″ 2.3GHz Dual-Core MacBook Pros a...
Focus Camera has clearance 2017 13″ 2.3GHz/128GB non-Touch Bar Dual-Core MacBook Pros on sale for $169 off Apple’s original MSRP. Shipping is free. Focus charges sales tax for NY & NJ residents... Read more
Amazon Prime Day deal: 9.7″ Apple iPads for $...
Amazon is offering new 9.7″ WiFi iPads with Apple Pencil support for $80-$100 off MSRP as part of their Prime Day sale, starting at only $249. These are the same iPads found in Apple’s retail and... Read more
Amazon Prime Day deal: 10% (up to $20) off Ap...
Amazon is offering discounts on new 2019 Apple AirPods ranging up to $20 (10%) off MSRP as part of their Prime Day sales. Shipping is free: – AirPods with Charging Case: $144.99 $15 off MSRP –... Read more
Amazon Prime Day deal: $50-$80 off Apple Watc...
Amazon has Apple Watch Series 4 and Series 3 models on sale for $50-$80 off Apple’s MSRP as part of their Prime Day deals with prices starting at only $199. Choose Amazon as the seller rather than a... Read more

Jobs Board

*Apple* Systems Architect/Engineer, Vice Pre...
…its vision to be the world's most trusted financial group. **Summary:** Apple Systems Architect/Engineer with strong knowledge of products and services related to Read more
*Apple* Graders/Inspectors (Seasonal/Hourly/...
…requirements. #COVAentryleveljobs ## Minimum Qualifications Some knowledge of agricultural and/or the apple industry is helpful as well as the ability to comprehend, Read more
Best Buy *Apple* Computing Master - Best Bu...
**710003BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Store Associates **Location Number:** 000171-Winchester Road-Store **Job Description:** Read more
Best Buy *Apple* Computing Master - Best Bu...
**709786BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Sales **Location Number:** 000430-Orange Park-Store **Job Description:** **What does a Read more
Geek Squad *Apple* Master Consultation Agen...
**709918BR** **Job Title:** Geek Squad Apple Master Consultation Agent **Job Category:** Services/Installation/Repair **Location Number:** 000106-Palmdale-Store Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.