TweetFollow Us on Twitter

Programming MultiFinder
Volume Number:3
Issue Number:11
Column Tag:Forth Forum

Programming for MultiFinder

By Jörg Langowski, MacTutor Editorial Board, Grenoble, France

Forth background processing under MultiFinder

As of October, there is a new operating system for the Macintosh which comes pretty close to real multitasking. The MultiFinder, also known as Juggler, was introduced; many of you are probably familiar with its operation by now.

This month we’ll see how to interface Mach2 and MacForth applications to the MultiFinder so that they use as little memory as possible, are friendly to other applications running in the same environment, and keep doing their job while they’re in the background.

Summary of FORTH multitasking

Multitasking Forth systems like Mach2 or MacForth, even before the advent of Juggler, already had a mechanism built in that is very similar to what Juggler does. When a task has nothing to do for a while, at certain strategic points in the program it passes control back to the task scheduler, who then calls up the next task.

This is not real multitasking since a task can be nasty and never let loose of the CPU once it has gained control, effectively stopping all other activity. In a real multitasking system, an interrupt-driven task scheduler would give control to the other processes anyway, avoiding such a dead-end situation. In a pseudo-multitasking environment such as Mach2 or MacForth, the task itself has the responsibility of not staying active for too long and letting the others have a turn. (The following examples, again, refer to Mach2. The same or similar Forth routines are provided in MacForth, so there should be no difficulty in transposing between the two.)

Task scheduling in Mach2 is done in a way largely transparent to the programmer. Words used for I/O routines such as KEY, ?TERMINAL, EMIT, and others, will contain a PAUSE, which is a word that returns control to the task scheduler. The idea being, of course, that during I/O operations there will usually be spare time to do other things. For long calculations without I/O in between, one would have to provide additional PAUSEs inside time-consuming loops.

What does PAUSE do exactly? I am not going to give you a disassembly of the task scheduler here (you could easily do that by yourself), but the task swapping is very simple and described in detail in the Mach2 manual. The registers used by the task are saved on the stack, and the next task entered or skipped depending on whether its STATUS field contains the value WAKE or SLEEP. WAKE, in fact, is the 16-bit value of a TRAP#n instruction, where the exception vector points to the task scheduler routine, while SLEEP is simply the value of a JMP instruction (with the address of the nex task directly following), so that we’ll jump to the next task without doing anything.

For tasks which are awake, the trap routine will then restore the registers and, if necessary, execute the vectored menu, control, or user data handling routines. After having done this, control will be given to the task, until PAUSE is called again.

One default Mach2 task, which is present in any Mach2 application, is the I/O task. It functions as the main event loop for the program and will distribute events to the tasks that they belong to (e.g. for a mouseclick it will determine which window it occurred in and call the event handling routines that belong to the task that owns the window). The source code of the I/O task is contained in the newest releases of Mach2 and therefore open to any modification, which is going to be helpful for the interfacing with MultiFinder that we’re about to do.

MultiFinder’s multitasking strategy

If you substitute GetNextEvent for PAUSE in the previous paragraph, you get a pretty good idea of what MultiFinder is doing. For Macintosh applications, the interface to the multitasking environment is this well-known trap, GetNextEvent. The Macintosh operating system follows a strategy very similar to that of the Forth multitasker: when GetNextEvent is called, it is assumed that the application has finished one (small) part of its work and is asking what to do next. If there are several null events in a row, MultiFinder assumes there is nothing more to do in the foreground and transfers control to a background application. This application then will be given a null event, and it is assumed that during such null events the program is doing some useful background activity. The background application will also receive update events if the window arrangement has changed. GetNextEvent, of course, had to be patched to implement the task switching strategy.

I am trying to outline it for you in the following, although I do not have all the necessary information; the MultiFinder development package, APDA document #KMSMFD, gives only hints as to what is happening. Nevertheless, if you are thinking of developing programs that take full advantage of the MultiFinder, you should of course get this brochure, full of development guidelines. Another part of the following information came from posts on BIX and other bulletin boards.

First, context switching from the foreground to any background application, while the foreground stays idle, will involve saving the registers and program counter of the CPU. Furthermore, applications might have accessed and changed low memory globals; so a copy of the Toolbox globals area is saved with each application, just like in Switcher. In addition, MultiFinder is intelligent enough to notice any trap patching that is going on when the application starts up for the first time (I suppose MultiFinder assumes that all this is taking place before the first call to GetNextEvent, or looks at the SetTrapAddress calls to see which changes are made). Those trap patches are also saved with the application, and changed appropriately on context switching. All this necessary switching information is saved in PCBs (process control blocks), which are located in memory just under the applications and just above the free memory and the system heap.

‘Context switching’ therefore means that the background application will have full control over the Macintosh, including any trap or low memory patches that have been made. The drawback is that there is quite a lot of switching overhead due to all the low memory stuff that has to be moved. (In the future, those problems will be taken care of by a memory management unit).

Clicking on any window that belongs to a background application will move that window to the front, activate it and move the previous foreground task into the background (just like Mach2 did all the time). In fact, together with the window that was clicked, all other windows associated with that same application are also moved in front of all the others. Such a set of windows that belong to one application is called a Layer. A new set of Toolbox routines, the Layer Manager, takes care of updating and maintaining the different window sets in a correct fashion.

When a background application is moved into the foreground, not only contexts are switched between the new and the old foreground application: also, a sequence of events occurs that seems to be very similar to the way Switcher changed from one application to another. In order to ensure correct scrap handling, any internal scrap maintained by the application has to be moved into the clipboard in a format that other applications can understand. This procedure is called scrap coercion and can be done in two different ways.

The recommended way is to implement Suspend/Resume events in the program. These events have an event code of 15 in the what field of the event record, with bit 0 set in the message field for Resume and cleared for Suspend events. When a Suspend event is received by the application, it should convert its internal scrap (i.e. the TE scrap) to the desk scrap, and on a Resume event take whatever is in the desk scrap and convert it to its internal format.

Applications that don’t understand Suspend/Resume events are forced to go through a more time-consuming process on switching: MultiFinder, like Switcher, simulates cutting/pasting to an imaginary desk accessory. Applications that support desk accessories have to do scrap coercion on that occasion, and the clipboard will be updated.

A third activity that has to occur is that the new frontmost window has to be activated while the old front window gets deactivated. MultiFinder will automatically, together with the Resume event, feed an activate event to the proper window when it is moved into the foreground, while the window going to the background receives a deactivate event. However, applications that fully support MultiFinder will not need these activate/deactivate events since they can do the necessary activations and deactivations on the Resume and Suspend events.

16-bit flag word:

bit(s) use

15 unused by MultiFinder

14 0 = application does not understand suspend and resume events

1 = application understands suspend and resume events

13 unused by MultiFinder

12 0 = application cannot do backgrounding

1 = application supports backgrounding

11 0 = application is not MultiFinder Aware

1 = application is MultiFinder Aware

0-10 unused by MultiFinder

32 bit word:

preferred memory size

32 bit word:

minimum memory size

Table 1: The SIZE ID=-1 resource.

To indicate the level of compatibility with the MultiFinder, the SIZE ID=-1 resource (table 1), known from Switcher, contains some new flags. Bit 14 of its 16-bit flag word indicates whether the application supports Suspend/Resume events (like under Switcher); bit 12 indicates whether the application should be periodically called and given a null event while the foreground task is idle; and bit 11 tells whether the necessary activation and decativation of the frontmost window are done automatically on Suspend/Resume events or whether additional activate/deactivate events have to be provided by MultiFinder. If your application is fully MultiFinder compatible, all of these bits should be set.

The two long words following the flag word indicate the preferred and minimum memory size, as before under Switcher.

Making Mach2 programs run in the background

The most interesting thing about MultiFinder is that it allows most existing applications to continue running in the background, if they are set up to perform activities while null events are received. Programs written in the Mach2 multitasking system are perfectly adapted to background processing, since the Forth multitasker keeps on going as long as each task calls PAUSE regularly. Events are taken care of by the I/O task and automatically distributed between the various other tasks. Null events will just transfer control from the I/O task to the next task in the list (see the main event loop at the end of listing 1; when a null event is received, the IOtask executes a PAUSE). Therefore, when a Mach2 application receives a null event, all its tasks will execute once in a row, until the IOtask gets control again and calls GetNextEvent. This will happen no matter whether the Mach2 program runs in the foreground or in the background.

So, even if your Mach2 program does not support suspend and resume events and the automatic window activation and deactivation on switching, you can still have it run in the background. Simply setting the canBackground bit, bit 12 in the flag word of the SIZE resource, will keep the program running. To illustrate this, you should now load the Reflections example from the Mach2 demo disk (Listing 2), which draws nice line patterns in a small window. The main loop contains a PAUSE so that this program is polite and lets the other tasks have a turn. TURNKEY the program and then change its canBackground bit to 1, using ResEdit. Also, set the preferred memory size to 100K and the minimum size to 80K; this is largely sufficient, and the default given by the Mach2 system is much higher. You can keep a SIZE resource with these settings in the MACH.RSRC file so that it will automatically be added to any turnkey application.

I suppose your Macintosh is running Juggler at this moment, if not, you’re out of luck. After you’ve turnkeyed and ResEdited the demo program, start it and you’ll see the patterns moving in the window; then click on any Finder window to move it to the foreground. You’ll notice that the lines continue to move in the background.

WaitNextEvent and modification of the IOTask

Satisfied? There is more we can do. The way our demo runs now, MultiFinder will wait until two successive null events have been received through GetNextEvent and on the third one transfer control to a background task. As long as the foreground task stays idle, the background tasks will be called one after the other. However, the foreground application still receives control periodically, getting a null event. This is because a priori we don’t know how long we may take control away from it, and it might have to do some ‘idling’ activities itself, such as blinking the caret. If the program had been properly designed to work with MultiFinder, we could have used a new trap that tells the system how long it may stay away before re-transferring control to the foreground application. This trap is called WaitNextEvent, and it is called as follows (Pascal syntax):

function WaitNextEvent (eventMask: Integer; VAR theEvent: EventRecord; 
sleep: longint; mouseRgn: RgnHandle): BOOLEAN;

Its trap code is $A860. The Forth interface to this trap is given in listing 1.

WaitNextEvent called with sleep and mouseRgn equal to 0 works just exactly like GetNextEvent. However, when sleep contains a nonzero value, that is supposed to be the number of ticks that the application may be ‘put to sleep’ by MultiFinder before being called again when there is no non-null event waiting. This means, if during idling you just want to blink the cursor twice a second, you may call WaitNextEvent with a sleep value of 30. When a non-null event like a key down or mouse click occurs, control will be transferred to the foreground routine immediately.

The mouseRgn region handle indicates a region inside which the cursor does not have to be changed upon mouse movement. When this handle is nonzero, any mouse movement outside the given region will generate a ‘mouse-moved’ event, which is an app4event (like Suspend and Resume) with event code=15 and $FA in the high byte of the event message. When mouseRgn is nil, no mouse-moved events will be generated.

The call to GetNextEvent is made by the IOTask under Mach2. We can now modify the IOTask in such a way that WaitNextEvent will be used instead. Listing 1 gives the details.

First, we have to verify that Juggler is running and the call to WaitNextEvent is a valid trap call. This can be done easily by comparing the trap address of WaitNextEvent to that of UnknownTrap ($A89F), which is never implemented. If the two values are different, Juggler is installed. If they are the same, we’ll have to call good old GetNextEvent.

Of course, this comparison won’t be done on every GetNextEvent call. We should set a flag at the beginning of our program that indicates the state of the system. The initialization code of a Mach2 application, however, is not readily accessible, so we catch the first call to the Forth word GetNextEvent and determine at that point whether we can WaitNextEvent or not. We then set a flag accordingly, which will be checked on every following GetNextEvent call. If we call WaitNextEvent, we won’t have to call SystemTask periodically, either; its function is taken over by WaitNextEvent.

With this modification the IOTask will take care of returning control to other background applications when null events are occurring. You might now think that one should put a value of some 3 to 30 ticks into the sleep parameter, since we don’t need to come back so often when nothing special is happening. This is not so; according to my experimentation, the maximum sensible value for sleep in the IOTask event loop is 1 (one). The reason for this is the way events are dispatched by the Forth system. The IOTask takes all pending events and calls the event handling routines of the frontmost Forth task during one turn of its execution. It only transfers control to the next Forth task when no more events are pending, i.e. the event returned is a null event. At this point, however, MultiFinder will give control to a background application and only return after sleep ticks have expired. Since the event queue has just been emptied, it is very likely that this time really elapses before control is returned to the foreground task with a null event and the Forth tasks can have a round of execution. Again, this round will stop at IOTask, wait for sleep ticks, and so on.

In practice this means that setting sleep to a value greater than 1 (maybe 2) will slow down the Mach2 system in an unacceptable manner. For instance, keystrokes are processed by the individual Forth tasks, not by the IOTask, which only puts them into the tasks’ keyboard buffers. If you set sleep to 30 ticks, you will then be typing at a rate of less than two letters a second. Although I am a slow typist, this slows me down too much...

Let this just be a warning to be careful with the sleep parameter; it might of course be set to higher values depending on what one wants the Forth application to do. For programs that run ‘background-only’, we might afford much longer naps.

If you modify the IOTask in the way indicated in listing 1, the Mach2 system won’t be slowed down too much and background activity will run a little more smoothly. You might also define a sleep parameter that can be changed while the tasks are running, by storing it in a variable close to the event table. That way it can be accessed from within the Mach2 program through an offset from EVENT-TABLE.

I have not yet changed the IOTask in a way to support Suspend/Resume events. This is pretty straightforward: one would have to define a vector in the user variable table where a vector to the Suspend/Resume handler is kept, and let the IOTask call it when the event is received. The IOTask would also deactivate, resp. activate the frontmost window by calling the activate handler.

Talking about sleep parameters for such a long time almost makes me fall asleep, so I’ll let you go for this month.

Happy Threading.

Listing 1: MultiFinder support for Mach2
\ © 1987 J.Langowski / MacTutor
\ with parts of the code © Palo Alto Shipping
\ add this code to the IOTASK code supplied by 
\ Palo Alto Shipping, and modify main event loop as indicated

.TRAP _WaitNextEvent $A860

CODE WaitNextEvent 
( eventMask VAR-eventRecord sleep mouseRgn -- flag )
 EXG  D4,A7
 CLR.W  -(A7)    \ function result
 MOVE.W  $E(A6),-(A7)\ eventMask
 MOVE.L $8(A6),-(A7) \ eventRecord
 MOVE.L $4(A6),-(A7) \ sleep
 MOVE.L   (A6),-(A7) \ mouseRgn
 ADDA.W #$10,A6
 _WaitNextEvent
 MOVE.W (A7)+,D0 \ flag -> D0
 EXT.L  D0\ extend sign
 MOVE.L D0,-(A6) \ push on Forth stack
 EXG  D4,A7
 RTS
END-CODE

Header JugglerThere -1 ,
\ initially -1 so that first call
\ to GetNextEvent will determine state

\  ========= The Main Loop  ===========

: DialogEvent? (  -  f  )
 \ If event is dialog event which should be handled
 \ by our application 
 \ (usually be being passed to DialogSelect),
 \ IsDialogEvent will return a true flag. If event
 \ should be handled as a normal, non-dialog event, 
 \ false will be returned.
 EVENT-RECORD CALL IsDialogEvent ;
 
: GetNextEvent (  - f )
 \ If an event occurs which should be handled,
 \ GetNextEvent will return a true flag.  
 \ The event code and any other event information 
 \ will be returned in the EVENT-RECORD.
 \ changed for Juggler support 26.8.87 JL
 [‘] JugglerThere @ CASE
 1 OF \ Yes, we can juggle
 EveryEvent Event-Record 1 0 WaitNextEvent 
 ENDOF
  0   OF   \ no, we can’t
 CALL SystemTask 
 \ built in here since WaitNextEvent doesn’t need it
 EveryEvent Event-Record CALL GetNextEvent  
 ENDOF
 -1   OFWNETrap# CALL GetTrapAddress
 UnkTrap# CALL GetTrapAddress
 = IF CALL SystemTask 0 
 ELSE 1 THEN 
 [‘] JugglerThere !
 EveryEvent EVENT-RECORD CALL GetNextEvent 
 ENDOF
 0 \ we should never get here
 ENDCASE
;
 
\ ===== (IOTASK) =====  
: (IOTask) {  | dialogflag eventflag --  }
 BEGIN
 BEGIN
 GetNextEvent  -> eventflag
 DialogEvent?  -> dialogflag

 dialogflag IF
 HandleDialog
 ELSE
 eventflagIF  HandleEvent  THEN
 THEN
 eventflag 0=
 UNTIL
 PAUSE
 AGAIN ;
Listing 2: Reflections demo from Mach2

\ Reflections
\ Mach2.12 Demo
\ 6/87
\ Palo Alto Shipping Company

\ Description: 
\ (xx1,yy1) and (xx2,yy2) are two points that travel 
\ around the reflections window. Their speeds are 
\ the delta values held in the DOT variables. When a 
\ point runs into a wall, it’s x or y speed is negated 
\ so that it bounces off the wall. All the while a line 
\ is drawn between the two points and the line drawn 20 
\ steps ago is erased.
  
ONLY FORTH DEFINITIONS  ALSO MAC
DECIMAL

\ QuickDraw Equates
$8 CONSTANT PatCopy
$B CONSTANT PatBic
$10CONSTANT PortRect

\ Window Size Variables
VARIABLEWTop
VARIABLEWLeft
VARIABLEWBottom
VARIABLEWRight
VARIABLEWWidth
VARIABLEWHeight

\ Positions \ Velocities
VARIABLE xx1VARIABLE xx1DOT
VARIABLE yy1VARIABLE yy1DOT
VARIABLE xx2VARIABLE xx2DOT
VARIABLE yy2VARIABLE yy2DOT

\ Menu constants and variables.
VARIABLE DeskName 252 VALLOT

$44525652 CONSTANT ‘DRVR’

CREATE AppleString 
\ Creating title string for AppleMenu.
$01 C,  \ Length byte.
$14 C,  \ Apple character.

\ Creating a window named ‘Reflections’.
NEW.WINDOWReflections
“ Reflections”   Reflections TITLE
#115 #315 #265 #465Reflections BOUNDS
ROUNDED VISIBLE NOCLOSEBOX NOGROWBOX
 Reflections ITEMS

\ ‘LinesTask’ is a task w/ 800 bytes of param stack.
#800 #1000 TERMINAL LinesTask

\ Give ‘Reflections’ a menubar.
NEW.MBAR ReflectMBar

NEW.MENUAppleMenu
AppleString AppleMenu TITLE
0 #998  AppleMenu BOUNDS
“ (Reflections;(-” AppleMenu ITEMS

NEW.MENUFileMenu
“ File” FileMenu TITLE
0 #999  FileMenu BOUNDS
“ Quit/Q” FileMenu ITEMS

: HandleDeskAcc { item# | saveport --  }
 ^ saveport CALL GetPort
 AppleMenu @ item# DeskName CALL GetItem     
 DeskName CALL OpenDeskAcc DROP
 saveport CALL SetPort  ;

: DoApple ( item# -  ) HandleDeskAcc ;

: DoFile ( item# -  ) DROP BYE ; 
 
: MbarHandler  ( item# menuID -  )
 CASE
 #998 OF DoApple ENDOF
 #999 OF DoFile  ENDOF
 ENDCASE  
 0 CALL HiliteMenu  ;

: RANGE { value hi lo - value flag }
 value hi value > lo value < OR NOT ;
 
: 4DUP ( n1 n2 n3 n4 - n1 n2 n3 n4 n1 n2 n3 n4 )
 #3 pick #3 pick #3 pick #3 pick ;
 
: GetWCoords { wptr | wrect --  }
 wptr PortRect + -> wrect
 wrect  W@ L_EXT WTop !
 wrect 2+ W@ L_EXT WLeft   !
 wrect 4 +W@ L_EXT WBottom !
 wrect 6 +W@ L_EXT WRight  !

 WBottom @WTop @ - WHeight !
 WRight @ WLeft @ -  WWidth !  ;
 
: Exit? ( - f ) 
 ?TERMINAL IF
 KEY IF BYE THEN
 THEN ;

: SetupReflect (  -  )
 Reflections CALL SetPort 
 CLS
 WWidth @ 3 /    xx1 !   #3 xx1DOT !
 WHeight @  yy1 !  #-4 yy1DOT !
 WWidth @ 3 / 2* xx2 !   #4 xx2DOT !
 WHeight @  yy2 !  #-3 yy2DOT ! ;
 
\ Draws a newline and leaves coords on stack.
: NewCoords ( - xx1 yy1 xx2 yy2 )
 xx1Dot @ xx1 +! yy1Dot @ yy1 +!
 xx2Dot @ xx2 +! yy2Dot @ yy2 +!

 xx1 @ 1 WWidth @ RANGE NOT
 IF xx1Dot @ NEGATE xx1Dot !
 THEN

 yy1 @ 1 WHeight @ RANGE NOT
 IF yy1Dot @ NEGATE yy1Dot !
 THEN

 xx2 @ 1 WWidth @ RANGE NOT
 IF xx2Dot @ NEGATE xx2Dot !
 THEN

 yy2 @ 1 WHeight @ RANGE NOT
 IF yy2Dot @ NEGATE yy2Dot !
 THEN ;
 
\ Leaves 40 coordinate pairs on the stack and draws the 
\ 1st 20 lines.
: First20Lines (  -  )
 #20 0 DO
 ReflectionsCALL SetPort
 PatCopyCALL PenMode
 NewCoords 4DUP
 CALL MoveToCALL LineTo
 LOOP ;

: LinesForever (  -  )
 BEGIN
 ReflectionsCALL SetPort
 PatCopyCALL PenMode
 NewCoords 4DUP
 CALL MoveTo
 CALL LineTo ( 21 complete sets on => 84 values)

 #83 ROLL #83 ROLL #83 ROLL #83 ROLL
 PatBic CALL PenMode ( and white out the n-21st line)
 CALL MoveTo   CALL LineTo
 exit?  AGAIN  ;
 
: Reflect (  -  )  SetUpReflect  First20Lines  LinesForever ;
 
: InitMBar (  -  )
 ReflectMBar   ADD
 ReflectMBar AppleMenu ADD
 ReflectMBar FileMenu ADD
 AppleMenu @ ‘DRVR’ CALL ADDRESMENU
 ReflectMBar @ CALL SetMenuBar
 CALL DrawMenuBar ;
 
: InitStructures (  -  )
 Reflections ADD
 Reflections CALL SelectWindow
 Reflections GetWCoords
 Reflections LinesTask BUILD 
 InitMBar ;

: Run ( taskptr -  )
 ACTIVATE
 [‘] MbarHandler MENU-VECTOR !
 ReflectMBar LinesTask MBAR>TASK
 Reflect ;

: BootLines (  -  )   InitStructures  LinesTask  Run  ; 
 
AAPL
$116.57
Apple Inc.
+0.26
MSFT
$48.70
Microsoft Corpora
+0.00
GOOG
$538.89
Google Inc.
+4.06

MacTech Search:
Community Search:

Software Updates via MacUpdate

Cyberduck 4.6 - FTP and SFTP browser. (F...
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
Maya 2015 - Professional 3D modeling and...
Maya is an award-winning software and powerful, integrated 3D modeling, animation, visual effects, and rendering solution. Because Maya is based on an open architecture, all your work can be scripted... Read more
Evernote 6.0.1 - Create searchable notes...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
calibre 2.11 - 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... Read more
Herald 5.0.1 - Notification plugin for M...
Note: Versions 2.1.3 (for OS X 10.7), 3.0.6 (for OS X 10.8), and 4.0.8 (for OS X 10.9) are no longer supported by the developer. Herald is a notification plugin for Mail.app, Apple's Mac OS X email... Read more
Firetask 3.7 - Innovative task managemen...
Firetask uniquely combines the advantages of classical priority-and-due-date-based task management with GTD. Stay focused and on top of your commitments - Firetask's "Today" view shows all relevant... Read more
TechTool Pro 7.0.6 - Hard drive and syst...
TechTool Pro is now 7, and this is the most advanced version of the acclaimed Macintosh troubleshooting utility created in its 20-year history. Micromat has redeveloped TechTool Pro 7 to be fully 64... Read more
PhotoDesk 3.0.1 - Instagram client for p...
PhotoDesk lets you view, like, comment, and download Instagram pictures/videos! (NO Uploads! / Image Posting! Instagram forbids that! AND you *need* an *existing* Instagram account). But you can do... Read more
SuperDuper! 2.7.3 - Advanced disk clonin...
SuperDuper! is an advanced, yet easy to use disk copying program. It can, of course, make a straight copy, or "clone" -- useful when you want to move all your data from one machine to another, or do... Read more
MacJournal 6.1.5 - Create, maintain, and...
MacJournal is the world's most popular journaling software for the Mac. MacJournal 6 adds a calendar mode that show entries from any journal, geolocation, word count, and progress tracking, as well... Read more

Latest Forum Discussions

See All

Quest for Revenge (Games)
Quest for Revenge 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: The great Kingdom of the west has fallen. The gods ignore the prayers of the desperate. A dark warlord has extinguished... | Read more »
Threadz is a New Writing Adventure for Y...
Threadz is a New Writing Adventure for You and Your Friends Posted by Jessica Fisher on November 21st, 2014 [ permalink ] In the tradition of round-robin storytelling, | Read more »
SteelSeries Stratus XL Hardware Review
Made by: SteelSeries Price: $59.99 Hardware/iOS Integration Rating: 4 out of 5 stars Usability Rating: 4.5 out of 5 stars Reuse Value Rating: 4.25 out of 5 stars Build Quality Rating: 4.5 out of 5 stars Overall Rating: 4.31 out of 5 stars | Read more »
ACDSee (Photography)
ACDSee 1.0.0 Device: iOS iPhone Category: Photography Price: $1.99, Version: 1.0.0 (iTunes) Description: Capture, perfect, and share your photos with ACDSee. The ACDSee iPhone app combines an innovative camera, a powerful photo... | Read more »
ProTube for YouTube (Entertainment)
ProTube for YouTube 2.0.2 Device: iOS Universal Category: Entertainment Price: $1.99, Version: 2.0.2 (iTunes) Description: ProTube is the ultimate, fully featured YouTube app. With it's highly polished design, ProTube offers ad-free... | Read more »
Weather or Not - Reports and Forecasts...
Weather or Not - Reports and Forecasts for your Calendar 1.0.0 Device: iOS iPhone Category: Weather Price: $2.99, Version: 1.0.0 (iTunes) Description: Weather or Not is a beautiful and intuitive way to check the weather and... | Read more »
Sago Mini Road Trip (Education)
Sago Mini Road Trip 1.0 Device: iOS Universal Category: Education Price: $2.99, Version: 1.0 (iTunes) Description: Go for a fun-filled drive with Jinja the cat. Pick a destination, select a vehicle and hit the road. What will Jinja... | Read more »
New Tower Defense Game, Kingdom Rush: Or...
New Tower Defense Game, Kingdom Rush: Origins, is Available Today Posted by Jessica Fisher on November 20th, 2014 [ permalink ] iPad Only App - Designed for the iPad | Read more »
Sunburn! (Games)
Sunburn! 1.0.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.0 (iTunes) Description: Your ship is gone. Your crew is scattered. One option remains. Gather your crew... and jump into the sun. Reunite your... | Read more »
Tapventures Review
Tapventures Review By Jennifer Allen on November 20th, 2014 Our Rating: :: ODDLY COMPELLINGUniversal App - Designed for iPhone and iPad Tapventures is an increasingly hands-off one-tap RPG, but expect it to hook you despite your... | Read more »

Price Scanner via MacPrices.net

64GB iPod touch on sale for $249, save $50
Best Buy has the 64GB iPod touch on sale for $249 on their online store for a limited time. Their price is $50 off MSRP. Choose free shipping or free local store pickup (if available). Sale price for... Read more
15″ 2.2GHz Retina MacBook Pro on sale for $17...
 B&H Photo has the 2014 15″ 2.2GHz Retina MacBook Pro on sale for $1799.99 for a limited time. Shipping is free, and B&H charges NY sales tax only. B&H will also include free copies of... Read more
New Logitech AnyAngle Case/Stand Brings Flexi...
Logitec has announced the newest addition to its suite of tablet products — the Logitech AnyAngle. A protective case with an any-angle stand for iPad Air 2 and all iPad mini models, AnyAngle is the... Read more
2013 15-inch 2.0GHz Retina MacBook Pro availa...
B&H Photo has leftover previous-generation 15″ 2.0GHz Retina MacBook Pros available for $1499 including free shipping plus NY sales tax only. Their price is $500 off original MSRP. B&H will... Read more
16GB Retina iPad mini on sale today for $199,...
 Staples has 2nd generation 16GB Retina iPad minis on sale for $199 on their online store for a limited time. Their price is $100 off MSRP. Choose free shipping or free local store pickup (if... Read more
Developers Start Designing Apps for Apple Wat...
Apple has announced the availability of WatchKit, software that gives developers a set of tools to easily create experiences designed specifically for Apple Watch. Apple’s developer community can now... Read more
C Spire Launches iPad Air 2 and iPad Mini 3 o...
C Spire has announced that iPad Air 2 with Wi-Fi + Cellular and iPad mini 3 with Wi-Fi + Cellular are now available on its 4G LTE network. C Spire offers both new iPads with a range of data plans... Read more
Are You On Your Last PC? – The ‘Book Mystique
Will your current PC be your last? Quite possibly so if you define “personal computer” as a traditional desktop or laptop form factor machine according to some commentators. So then, the upshot that... Read more
Save up to $180 on MacBook Airs with Apple re...
The Apple Store has Apple Certified Refurbished 2014 MacBook Airs available for up to $180 off the cost of new models. An Apple one-year warranty is included with each MacBook, and shipping is free.... Read more
16GB iPad mini available for $219, save $30
Walmart has 16GB iPad minis (1st generation) available for $219 on their online store. Their price is $30 off MSRP. Choose free shipping or free store pickup (if available). Price for online orders... Read more

Jobs Board

*Apple* Solutions Consultant (ASC)- Retail S...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple 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* Store Leader Program - College Gradu...
Job Description: Job Summary As an Apple Store Leader Program agent, you can continue your education as you major in the art of leadership at the Apple Store. You'll 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
Senior Event Manager, *Apple* Retail Market...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global event strategy. Delivering an overarching brand story; in-store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.