TweetFollow Us on Twitter

External Windows 2
Volume Number:7
Issue Number:4
Column Tag:XCMD Corner

Related Info: Window Manager Event Manager

More on External Windows

Donald Koscheka, Contributing Editor

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

Let’s see, the last time we left off, we were busy examining the external window system in HyperCard 2.0. Over the past few months, I’ve had an opportunity to explore the innards of HyperCard 2.0 in great detail. On balance, I ‘m not altogether disappointed although I do find that the windowing system can get a little awkward for very sophisticated applications. For example, I found that it would be nice to have one xcmd create an external window and have yet another xcmd manage that window. HyperCard 2.0 does not allow this; the xcmd must be created in the xcmd that will “own” that window. This is important to note when programming xcmds for external windows. When an event occurs in your window, the event will be dispatched to the xcmd that created the window. HyperCard must keep some sort of internal list of which xcmds own which windows.

In my last column, I presented an event loop for handling external windows. As I mentioned, external window events fall into two categories: “toolbox” level events such as update, activate and the like and “HyperCard” events that are created and dispatched by HyperCard. This month, we will look at some of the more arcane window management functions in HyperCard 2.0 and try to cast them in a light that makes them more useful than esoteric.

Window XCMDs

For the most part, xcmds that manage windows look like standard Macintosh event loops without the loop. The xcmd does not call getnextevent or waitnextevent directly. Rather, it gets an event from HyperCard. Each activation of the xcmd responds to exactly one event and then passes control back to HyperCard. This means that you don’t need to loop back to the beginning of the event loop. You process the current event and then return.

The significance of this last paragraph cannot be overstated. If you are an experienced xcmd programmer, you know that Hypercard unloads your xcmd resource after each activation. Much of the slownesss of xcmds can be attributed to the loading in of the resource on each activation.

This is not acceptable for windowing systems that need to flash a cursor on null events or do some reasonably fast processing of events. In these cases, you might do well to try your luck with a new Hypercard callback: XWHasInterrupt():

in Pascal:

{1}

Procedure XWHasInterruptCode( paramPtr : XCmdPtr; window :WindowPtr; 
HaveCode: Boolean);

in “C”:

/* 2 */

pascal void XWHasInterruptCode( XCmdPtr paramPtr, WindowPtr window, boolean 
HaveCode );

This routine will permanently lock the owning xcmd into memory. Apple advises that the routine should be used with extreme prudence as it can seriously tax HyperCard’s heap. By keeping the routine locked in memory, the code should theoretically perform faster although I haven’t noticed any dramatic improvements. By the way, the affected window must have been created using a call to NewXwindow. Don’t mix toolbox windows with HyperCard external windows -- your system will behave unpredicably if it behaves at all. HyperCard uses this window pointer to determine which xcmd is being affected by the callback. Get in the habit of always declaring your windows in the xcmd layer. If you have any old code lying around that creates windows directly, either fix it to work with the HyperCard windowing scheme or throw the code out. I rewrote all my window management code and found that the stuff works a lot better that way. It’s not a big deal: you first create the window with newxwindow and then wait for the xopenevt to be passed to the xcmd that owns the window. For further details, refer to the March, 91 issue of this column.

Now back to the fragmentation problem: XWHasInterruptCode locks your resource into memory making it a non-relocatable object for the duration (this implies that you can store pointers to routines et al in the source code but this is better avoided as a point of practice). Locked objects can seriously impact memory management in HyperCard which massages the heap rigorously. You can mitigate fragmentation by moving your code high in the heap where it will do the least amount of harm. Of course, you can’t move the code from inside itself, (not that this is impossible, you should consider this as an interesting problem in its own right). You can’t move your xcmd directly because HyperCard has locked it down so that it can invoke the callback libraries as subroutines. To move the xcmd height in memory, you call yet another callback:

{3}

Procedure XWAlwaysMoveHigh( paramPtr : XCmdPtr; window: WindowPtr; moveHigh 
: Boolean );

or

/* 4 */

pascal void XWAlwaysMoveHigh( XCmdPtr paramPtr, WindowPtr window, boolean 
movehigh );

If you set the movehigh flag to true, your xcmd will be moved high when it is loaded. Now this will ordinarily slow the xcmd down because first it must be loaded into memory and then moved up to the top of the heap. It seems to me that if you’re going to call this routine, you should lock the xcmd in memory also so that this process does not get repeated on every invocation of the xcmd (remember that xcmds get unloaded after each invocation as rule).

Now that the xcmd is high in the heap and is locked into memory, we can really start having some fun. The next callback we will look at allows us to make our xcmd reentrant:

{5}

Procedure XWAllowReentrancy( paramPtr; XCmdPtr; window: windowPtr; allowSysEvts: 
Boolean; allowHCEvts: Boolean );

or

/* 6 */

pascal void XWAllowReentrancy( XCmdPtr paramPtr, windowPtr window, boolean 
allowSysEvts, boolean allowHCEvts);

Use this callback to tell HyperCard that the xcmd can accept re-entrant events. Apple provided the xcmd mainly to handle the case where an xcmd executes a script and, during the script execution, may receive an event for one of its windows. This is actually more common than you might expect -- the user may switch out of HyperCard using Multifinder in which case your xcmd needs to be called back to handle the suspend/resume events. Another case for reentrancy is when your xcmd creates a window that needs to be updated while the xcmd is still running. You reach this state by implementing a modaldialog loop in your xcmd or by executing a script from within the xcmd. While the script is executing, the user may change the window ordering causing the your window to receive an update event (if it’s invalRgn changes of course).

In the documentation I received with Hypercard 2.0, Apple warns us that writing re-entrant code is difficult and that some development systems may not support re-entrancy. Apple refers the programmer to tech note #256 for further details (Stand Alone Code ad nauseum). Whether you ever plan to support re-entrancy or not, I suggest you read this tech note. It’s chock full of really good information -- the kind of tech note that I like to leave on my coffee table for guests to browse through when they come visiting.

An Example

Listing 1 depicts a window management xcmd that uses these callbacks and more. This xcmd allows us to specify three pieces of information for each window: the name, the rectangle and the type. Notice that the rectangle is converted to a QuickDraw rectangle from a HyperCard rectangle using the callback STRTORECT. This is a new callback that accepts a single string of the form below and converts it to a qd rect (in HyperCard, rects are specified as left, top, right, bottom: in QuickDraw they are specified as top,left,bottom, right). It’s important to allow the user to specify the rect in the most common vernacular, in this case, HyperTalk.

The xwindoids xcmd is invoked thusly:

--7

 xwindoids “Name of the new window”, “left,top,right,bottom”, style

where style can be any of the window styles specified in Inside Macintosh plus the floating HyperCard window type: “Palette”. To create a standard window, do this:

--8

 xwindoids “Hello World”, “0,0,300,200”, “documentProc”

Notice that the window is set to the upper left portion of the screen. The xcmd automatically centers the window so you need not worry about the actual screen coordinates. If this is not acceptable, comment out the center window code or write a move window xcmd, whichever you’re more comfortable with.

Dialogs present a different problem to window management in HyperCard. When we create a new window in the document layer of HyperCard, it shares the event loop with HyperCard (if effect, document windows in HyperCard are modeless dialogs). To make a modal dialog, we need to “take over” the event loop. This cannot be done easily once the window is in the HyperCard document layer. The solution is to bypass the layer from the outset. In listing 1, we first check to see if the window is a dBoxProc type (modal dialog). If not, we add it to the appropriate window layer with a call to NewXWindow (notice that Palettes automatically float).

If the window is to be a modal dialog, we first move the xcmd high and then lock it down. Reentrancy is not needed since we won’t return control to HyperCard until the user dismisses the dialog. Notice also that dialog windows need a fourth parameter:

--9

 xwindoids “DialogWindow”, “0,0,300,200”, “dBoxProc”, DITL_ID

where DITL_ID is the resource id of the ditl to be used by this dialog. If you are using a dialog window, you must specify the DITL or the xcmd will fail.

Once the xcmd is moved and locked, we can load in the DITL and detach it from the resource fork (this must be done or the window will crash on its next invocation -- DisposDialog disposes the DITL). From this point out, we run the dialog using modal dialog. The modalFilter proc checks to see if return or enter was pressed and also hilites item 1 which I ALWAYS specify as the default action button.

Once the dialog is dismissed, we close it down and return to HyperCard.

Listing 1 works for all styles of windows although its approach is rather unconventional. I haven’t found a way to put modal windows in the HyperCard document layer yet so you may want to play around with the code to see what you can discover. If you do move the modal dialog code into the HyperCard event processor, you MUST specify that the xcmd has interrupt code since modaldialog relies on a pointer to modalFilter. Time and energy prevent me from exploring this avenue any further but I’d love to hear from anyone who is successful in makeing this happen (no cheating -- you can’t rewrite ModalDialog which is the easy solution).

Have fun, see what you can discover on your own and let me know what you’d like to see in the future.

One last thing. You will notice that my callbacks are specified in Uppercase. This is because I converted the MPW HyperXLib to a Think Library without knowing about the option in the converter that would have permitted me to use the actual entry point names. I haven’t bothered to change this yet because Symantec just sent me their version of the Library. I will be using that in the future and my callbacks will have the correct case sensitivity.

Listing 1

/************************************/
/* A sample XCMD for Hypercard*/
/* 2.0 that displays and handles */
/* external windows and dialogs. */
/* */
/* Well-behaved XCMDs for HC2.0  */
/* will respond to the ! and ?*/
/* requests by returning version*/
/* and usage information  */
/* respectively. */
/* */
/* ----------------------------  */
/* ©1991, Donald Koscheka */
/* All Rights Reserved    */
/************************************/

/*
 Project:

 MacTraps
 HyperXLib-- Hypercard 2.0 callback library available from 
 Apple Computer, Inc.
 
 xwindoid.c (contents of listing 1)

 Set Project Type:
 Type == XCMD | XFCN
 Name == xwindoid
 id == -32768..32767
 
 Usage
 
 xwindoid “?”    -- XCMD 
 xwindoid “!”
 put the result
 
 OR     -- XFCN
 
 Put xwindoid( “?” )
 Put xwindoid( “!” )
 
  Parameters:
 
 xwindoid “name”, rect, style, dlgID
 
 name == the name of the window
 rect == the rect of the window
 style== dBoxProc, documentProc, palette,  
 dlgID== dialog id( modal dialogs only).
*/

#include<SetUpA4.h>
#include<string.h>
#include<HyperXCMD.h>
 
#ifndef NIL
 #define NIL(void *)0L
#endif

#define ETX 0x03 
#define BS0x08   
#define TAB 0x09
#define LF0x0A
#define NEWLINE  0x0D
#define CR0x0D
#define LEFT_ARROW 0x1C
#define RIGHT_ARROW0x1D
#define UP_ARROW 0x1E
#define DOWN_ARROW 0x1F

/* Multifinder events and masks  */
#ifndef MouseMovedEvt
 #defineMouseMovedEvt0xFA 
#endif

#ifndef SuspendResumeEvt
 #defineSuspendResumeEvt  0x01
#endif

#ifndef ResumeEvtMask
 #defineResumeEvtMask0x01
#endif

#ifndef ConvertScrapMask
 #defineConvertScrapMask  0x02
#endif

#define palette  0x80

pascal void HandleHCEvent( XCmdPtr pp );
pascal Boolean modalFilter( DialogPtr dlg, EventRecord *evt, short *itemhit 
);

void  CenterWindow( WindowPtr wptr, short isFront )
/***************************
* Center a window in the current
* screen port.  Note: Does not
* attempt to work with multi-screen
* systems.
*
* This code is courtesy of Steve
* Maller of Apple Computer Inc.
* Thanks Steve.
***************************/
{
 short  hWindSize = wptr->portRect.right - wptr->portRect.left;
 short  vWindSize = wptr->portRect.bottom - wptr->portRect.top;
 short  hSize = wptr->portBits.bounds.right - wptr->portBits.bounds.left;
 short  vSize = wptr->portBits.bounds.bottom - wptr->portBits.bounds.top;
 
 MoveWindow( wptr, 
 ( hSize - hWindSize ) / 2, 
 ( vSize - vWindSize + 20) / 2,
 isFront
 );
}

void Concat( char*str1, char*str2 )
/*****************************
* Append string 2 to the end of
* string 1.  Both strings are 
* pascal-format strings.
*
* str1 must be large enough to hold
* the new string and is assumed to 
* be of Type Str255 (a pascal string)
*****************************/
{
 BlockMove( str2 + 1, str1 + str1[0] + 1, (long)str2[0]);
 str1[0] += str2[0];
}

pascal void main( XCmdPtr pp )
/**************************************
* MAIN ENTRYP POINT FOR THIS XCMD
* 
* params[0] = the name of the window
* params[1] = the rect of the window (left,top,right,bottom)
* params[2] = the window style (dBoxProc, documentProc, palette)
**************************************/
{
 Handle answer = NIL;
 char   *str;
 long   len;
 WindowPtrwind;
 TEHandle hTE;
 Rect   bounds;
 short  style    = documentProc;
 char   title[32];
 char   temp[64];/* no need to hog the stack here */
 long   dlgID    = 0;
 
 pp->returnValue = NIL;

 if( pp->paramCount < 0 ){/* Have an event for one of our windows */
 HandleHCEvent( pp );
 return;
 }
 
 if (pp->paramCount == 1){
 if ( **(pp->params[0]) == ‘!’ ){
 pp->returnValue = PASTOZERO(pp,”\pxwindoid XCMD, version 1.1, ©1991, 
Donald Koscheka”);
 return;
 }
 
 if ( **(pp->params[0]) == ‘?’ ){
 pp->returnValue = PASTOZERO(pp,”\pxwindoid name,rect,style”);
 return;
 }
 }
 
 /* if we get this far, the caller must be creating a new window */
 title[0] = 0; /* the default name */
 Concat( title, “\pUntitled”);
 if( pp->params[0] ){
 HLock( pp->params[0] );
 ZEROTOPAS( pp, *(pp->params[0]), &title );
 HUnlock( pp->params[0] );
 }
 
 /* the default rectangle if one not specified */
 bounds.top = bounds.left = 0;
 bounds.bottom = 200;
 bounds.right = 300;
 if( pp->params[1] ){
 HLock( pp->params[1] );
 ZEROTOPAS( pp, *(pp->params[1]), &temp );
 STRTORECT( pp, temp, &bounds );
 HUnlock( pp->params[1] );
 }
 
 if( pp->params[2] ){
 HLock( pp->params[2] );
 ZEROTOPAS( pp, *(pp->params[2]), &temp );
 
 /* the poor man’s parser */
 if( STRINGEQUAL( pp, temp, “\pDOCUMENTPROC” )) style = documentProc;
 if( STRINGEQUAL( pp, temp, “\pDBOXPROC” )) style = dBoxProc;
 if( STRINGEQUAL( pp, temp, “\pPALETTE” )) style = palette;
 HUnlock( pp->params[2] );
 }
 
 /* these callback will bomb if window is not valid */
 XWALWAYSMOVEHIGH( pp, wind, TRUE ); 
 XWHASINTERRUPTCODE( pp, wind, TRUE );

 if( style == dBoxProc ){
 GrafPtroldPort;
 short  itemHit;
 Handle items;
 
 if( pp->params[3] ){
 HLock( pp->params[3] );
 ZEROTOPAS( pp, *(pp->params[3]), &temp );
 dlgID = STRTONUM( pp, temp );
 HUnlock( pp->params[3] );
 }
 
 items = GetResource( ‘DITL’, dlgID );
 DetachResource( items ); 
 wind = NewDialog( NIL, &bounds, title, FALSE, dBoxProc,-1L,FALSE,0L, 
items );
 CenterWindow( wind, TRUE );
 GetPort( &oldPort );
 SetPort( wind );
 ShowWindow( wind );
 
 do{
 ModalDialog( modalFilter, &itemHit );
 }while( itemHit != OK );
 
 HideWindow( wind );
 DisposDialog( wind );
 SetPort( oldPort );
 }
 else{
 wind = NEWXWINDOW( pp, &bounds, title, FALSE, style, 
 FALSE, style==palette);
 CenterWindow( wind, TRUE );
 }
}

pascal Boolean modalFilter( DialogPtr dlg, EventRecord *evt, short *itemhit 
)
/************************************
* general filter proc, accepts return and
* enter as ok and hilites the ok button.
*
* the ok button is always item 1.
*
* Notice that ModalDialog always accesses
* this routine via a pointer.  If your
* code implemented modalDialog in HandleHCEvent
* then you will need to make sure that
* XWHasInterrupt is set to true.
************************************/
{
 int    thenum;
 Handle theitem;
 Rect   thebox;
 char   cc;
 
 short  iTyp;
 Handle iHdl;
 Rect   iBox;
 ControlHandle okbutn;
 
 switch( evt->what ){
 case keyDown:
 cc = (char)evt->message & charCodeMask;
 GetDItem( dlg, OK, &iTyp, &okbutn, &iBox);
 if( (*okbutn)->contrlHilite != 255 ){
 SetCtlValue( okbutn, 1 );
 if(cc == CR || cc == ETX ){
 *itemhit = OK;
 return TRUE;
 }
 }
 break;
 
 case updateEvt:
 GetDItem( dlg, OK, &iTyp, &okbutn, &iBox);
 if( (*okbutn)->contrlHilite != 255 ){
 PenSize(3,3);
 InsetRect(&iBox,-4,-4);
 FrameRoundRect(&iBox,16,16);
 PenNormal();
 } 
 break;
 }/* event switch */

 return FALSE;
}

pascal void HandleHCEvent( XCmdPtr pp )
/**********************************
* Handle events in our xWindows  
* returns true if the event was handled ok
*
**********************************/
{
 XWEventInfoPtr  ip= pp->params[0];
 WindowPtrwhichWindow;
 short  windoPart;
 TEHandle hTE;
 Rect   bounds;
 Point  hit;
 char   theKey;
 GrafPtroldPort;
 short  extend;
 
 pp->passFlag = TRUE;/* seems to be more often the case */
 
 switch( ip->event.what ){
 case mouseDown:
 windoPart = FindWindow( ip->event.where, &whichWindow );
 
 if( whichWindow )
 switch ( windoPart ){
 case inGoAway:
 if (TrackGoAway( whichWindow, ip->event.where) ){
 CLOSEXWINDOW( pp,whichWindow );
 pp->passFlag = FALSE;
 }
 break;

 case inDrag:
 /* handled by hypercard */
 break;
 
 case inGrow:
 break;
 
 case inContent:
 if (whichWindow == FrontWindow() ){
 GetPort( &oldPort );
 SetPort( ip->eventWindow );
 
 SetPort( oldPort );
 }else
 SelectWindow( whichWindow );

 pp->passFlag = FALSE;
 break;
 
 default: 
 break;
 }/* window part */
 break;
 
 case mouseUp:
 break;
 
 case keyDown:
 case autoKey: 
 /* the command key will be handled by hypercard */
 GetPort( &oldPort );
 SetPort( ip->eventWindow );
 theKey  = ip->event.message & 0xFF;
 
 SetPort( oldPort );
 pp->passFlag = FALSE;
 break;
 
 case activateEvt:
 if ( ip->event.modifiers & activeFlag )
 BEGINXWEDIT( pp, ip->eventWindow );
 else
 ENDXWEDIT( pp, ip->eventWindow );
 break;
 
 case updateEvt:
 /* hypercard converts dialogs to 0x14 kind? */
 if(((WindowPeek)(ip->eventWindow))->windowKind != 0x14) {
 BeginUpdate( ip->eventWindow );
 EndUpdate( ip->eventWindow );
 }
 break;
 
 case app4Evt:
 {
 unsigned char *evtType = &(ip->event.message);
 
 switch( *evtType ){
 case MouseMovedEvt:
 break;
 
 case SuspendResumeEvt:
 break;
 }
 }
 break;

 /****************************************/
 /*     THE HYPERCARD EVENTS*/
 /****************************************/
 case xOpenEvt:
 SetPort( ip->eventWindow );
 ShowWindow( ip->eventWindow );
 break;
 
 case xCloseEvt:
 HideWindow( ip->eventWindow );
 break;
 
 case xGiveUpEditEvt:
 break;

 case xEditUndo:
 break;
 
 case xEditCut:
 break;
 
 case xEditCopy:
 break;
 
 case xEditPaste:
 break;
 
 case xEditClear:
 break;
 
 default:
 GetPort( &oldPort );
 SetPort( ip->eventWindow );
 GetMouse( &hit );
 
 pp->passFlag = FALSE;
 SetPort( oldPort );
 }/* switch theEvent->what */
}

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

A Better Finder Rename 9.52 - File, phot...
A Better Finder Rename is the most complete renaming solution available on the market today. That's why, since 1996, tens of thousands of hobbyists, professionals and businesses depend on A Better... Read more
OmniFocus 2.2.3 - GTD task manager with...
OmniFocus helps you manage your tasks the way that you want, freeing you to focus your attention on the things that matter to you most. Capturing tasks and ideas is always a keyboard shortcut away in... Read more
TinkerTool 5.4 - Expanded preference set...
TinkerTool is an application that gives you access to additional preference settings Apple has built into Mac OS X. This allows to activate hidden features in the operating system and in some of the... Read more
Tinderbox 6.3.1 - Store and organize you...
Tinderbox is a personal content management assistant. It stores your notes, ideas, and plans. It can help you organize and understand them. And Tinderbox helps you share ideas through Web journals... Read more
Parallels Desktop 10.2.2 - Run Windows a...
Parallels Desktop is simply the world's bestselling, top-rated, and most trusted solution for running Windows applications on your Mac. With Parallels Desktop for Mac, you can seamlessly run both... Read more
Adobe Premiere Pro CC 2015 9.0.1 - Digit...
Premiere Pro CC 2015 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Premiere Pro customer). Premiere Pro CS6 is still available for... Read more
Adobe After Effects CC 2015 13.5.1 - Cre...
After Effects CC 2015 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous After Effects customer). After Effects CS6 is still available... Read more
Adobe Creative Cloud 2.2.0.129 - Access...
Adobe Creative Cloud costs $49.99/month (or less if you're a previous Creative Suite customer). Creative Suite 6 is still available for purchase (without a monthly plan) if you prefer. Introducing... Read more
Tower 2.2.3 - Version control with Git m...
Tower is a powerful Git client for OS X that makes using Git easy and more efficient. Users benefit from its elegant and comprehensive interface and a feature set that lets them enjoy the full power... Read more
Apple Java 2015-001 - For OS X 10.7, 10....
Apple Java for OS X 2015-001 installs the legacy Java 6 runtime for OS X 10.11 El Capitan, OS X 10.10 Yosemite, OS X 10.9 Mavericks, OS X 10.8 Mountain Lion, and OS X 10.7 Lion. This package is... Read more

Domino Drop (Games)
Domino Drop 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: Domino Drop is a delightful new puzzle game with dominos and gravity!Learn how to play it in a minute, master it day by day.Your... | Read more »
OPERATION DRACULA (Games)
OPERATION DRACULA 1.0.1 Device: iOS Universal Category: Games Price: $5.99, Version: 1.0.1 (iTunes) Description: 25% off launch sale!!! 'Could prove to be one of the most accurate representations of the Japanese bullet hell shmup... | Read more »
Race The Sun (Games)
Race The Sun 1.01 Device: iOS iPhone Category: Games Price: $4.99, Version: 1.01 (iTunes) Description: You are a solar craft. The sun is your death timer. Hurtle towards the sunset at breakneck speed in a futile race against time.... | Read more »
Tap Delay (Music)
Tap Delay 1.0.0 Device: iOS Universal Category: Music Price: $4.99, Version: 1.0.0 (iTunes) Description: Back in the “old days”, producers and engineers created delay and echo effects using tape machines. Tap Delay combines the warm... | Read more »
This Week at 148Apps: July 20-24, 2015
July is Heating Up With 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 »
Red Game Without A Great Name (Games)
Red Game Without A Great Name 1.0.3 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.3 (iTunes) Description: The mechanical bird is flying through an unfriendly, Steampunk world. Help it avoid obstacles and deadly... | Read more »
Warhammer: Arcane Magic (Games)
Warhammer: Arcane Magic 1.0.2 Device: iOS Universal Category: Games Price: $9.99, Version: 1.0.2 (iTunes) Description: Engage in epic battles and tactical gameplay that challenge both novice and veteran in Warhammer: Arcane Magic, a... | Read more »
Mazes of Karradash (Games)
Mazes of Karradash 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: The city of Karradash is under attack: the monsters of the Shadow Realms are emerging from the depths.No adventurer is... | Read more »
Battle Golf is the Newest Game from the...
Wrassling was a pretty weird - and equally great - little wressling game. Now the developers, Folmer Kelly and Colin Lane, have turned their attention to a different sport: golfing. This is gonna be weird. [Read more] | Read more »
Qbert Rebooted has the App Store Going...
The weird little orange... whatever... is back, mostly thanks to that movie which shall remain nameless (you know the one). But anyway it's been "rebooted" and now you can play the fancy-looking Qbert Rebooted on iOS devices. [Read more] | Read more »

Price Scanner via MacPrices.net

2015 13-inch 2.7GHz Retina MacBook Pro on sal...
B&H Photo has the new 2015 13″ 2.7GHz/128GB Retina MacBook Pro on sale today for $1199 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more
2.8GHz Mac mini available for $988, includes...
Adorama has the 2.8GHz Mac mini available for $988, $11 off MSRP, including a free copy of Apple’s 3-Year AppleCare Protection Plan. Shipping is free, and Adorama charges sales tax in NY & NJ... Read more
Updated Mac Price Trackers
We’ve updated our Mac Price Trackers with the latest information on prices, bundles, and availability on systems from Apple’s authorized internet/catalog resellers: - 15″ MacBook Pros - 13″ MacBook... Read more
High-Precision Battery Fuel Gauge IC Extends...
Renesas Electronics Corporation has announced its new lithium-ion (Li-ion) battery fuel gauge IC, the RAJ240500, designed to extend battery life for connected mobile devices such as tablets, notebook... Read more
27-inch 3.3GHz 5K iMac on sale for $1799, $20...
B&H Photo has the 27″ 3.3GHz 5K iMac on sale for $1799 including free shipping plus NY tax only. Their price is $200 off MSRP, and it’s the lowest price available for this model from any Apple... Read more
Twelve South Free Dual Screen Backgrounds Co...
Twelve South has posted a second collection of travel Desktop photos, noting: For the Twelve South team, a vacation is never just a vacation. It’s a time to try out new prototypes on the road, visit... Read more
Apple Refurbished iMacs available for up to $...
The Apple Store has Apple Certified Refurbished iMacs available for up to $380 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 27″ 3.5GHz 5K iMac – $1949 $... Read more
Tablets: Why Microsoft’s Surface Is Soaring W...
In contrast to Apple’s record fiscal third quarter reported this week, Microsoft had a miserable latest quarter with its revenues falling by 5.1 percent, hammered by ongoing weak PC demand, and... Read more
Sale! 13″ 1.6GHz/256GB MacBook Air for $1099,...
B&H Photo has the 13″ 1.6GHz/256GB MacBook Air on sale for $1099 including free shipping plus NY tax only. Their price is $100 off MSRP, and it’s the lowest price available for this model. Read more
iPad mini 4 To Be Upgraded To iPad Air 2 Spec...
There’s a certain inevitability about making Apple product predictions this time of year. Come September, we can pretty reliably count on the release of refreshed iPhones, along with the iOS 9... Read more

Jobs Board

*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
*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
*Apple* Customer Experience (ACE) Leader - A...
…management to deliver on business objectives Training partner store staff on Apple products, services, and merchandising guidelines Coaching partner store staff on Read more
Project Manager - *Apple* Pay Security - Ap...
**Job Summary** The Apple Pay Security team is seeking a highly organized, results-driven Project Manager to drive the development of Apple Pay Security. If you are Read more
*Apple* TV Product Design Internship (Spring...
…the mechanical design effort associated with creating world-class products with the Apple TV PD Group. Responsibilities will include working closely with manufacturing, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.