TweetFollow Us on Twitter

Fat Bits
Volume Number:2
Issue Number:6
Column Tag:C Workshop

Mouse DA shows off Fat Bits

By Rick Flott, FlottWare, Chandler, AZ

Mouse Position Desk Accessory

Introduction

Setting up screen graphics on the Mac can be a very tedious and time consuming job. Previously I have used "Mouse Position" desk accessories (DA's) to show the position of the mouse, but none of them had the features I wanted. So as a true programmer I wrote one myself. I borrowed some ideas from others and added a few new ones of my own.

First, I must give credit where it is due. I used an old DA called Magnifying Glass to get a "Fat Bits" view of the screen. I really thought the "Fat Bits" was neat, but wanted other information. This Mouse Position DA also has this feature, but uses it in a little different way.

Using the Mouse Position DA

The window created by the Mouse Position DA looks like this -

The top line gives the name of the window the cursor is currently over. The next two lines (labeled 'L' and 'G') give the local and global coordinates of the mouse (both horizontal and vertical portions are given). The bottom graphics give a "Fat Bits" view of the mouse position. There are a few differences between these "Fat Bits" and others you may have seen.

First, the actual position of the cursor is in the center of the screen (not in the top left corner). Second, the gray lines symbolize the real point (as you all know from reading Inside Macintosh - points do not occupy space, they are at the intersection of infinitely thin horizontal and vertical grid lines). The "hot spot" of the cursor is the point immediately below and to the right of the gray "crosshairs" (the tip of the paintbrush of the MacPaint Icon shown in the window). The "crosshairs" do not cover up any pixels, they just split the rectangle surrounding the cursor into four planes.

There are also a few other features in this DA -

• when the mouse is over the desktop, the window name is set to "DeskTop" and no local coordinates are shown (since they don't exist).

• the window name, local, and global coordinates can be "Cut" or "Copied" to the clipboard and "Pasted" into your program.

• when the CapsLock key is down and the coordinates are Cut or Copied, they are appended to the clipboard. This is very handy when setting up rectangles or other complex graphics that require multiple points. Just press CapsLock and start Copying!

• remember - in most applications Cut and Copy only work on the topmost window, hence the Mouse Position window must be in front for these commands to work.

Code Description

As in any desk accessory, 5 routines must be present -

• open (initializes the DA)

• close (stops the DA)

• control (receives commands from system)

• prime

• status

The latter two routines do not need to perform any functions, but they must be present.

The open routine in the Mouse Position DA is the "main()" of this C program. It allocates the DA window from the heap, sets up the font for this window, and draws the "static" portion of the window. It also stores the reference number of the DA in the windowKind field of the window. This is very important since this the only way the Mac knows that this is a "system" window and to pass the proper events to it and not to the running application. In addition to this, the pointer to the window is kept in the device control entry for retrieval later on. Remember, a desk accessory is viewed as 5 separate routines called by the system (unlike an application).

The Close routine does the opposite of the open. It releases the memory used by the window and resets the proper fields in the device control entry record.

The Control routine does all the work. It takes commands from the system (passed to it when the application calls SystemTask, SystemEdit, or SystemClick) and processes them. In this DA, only two commands are processed - accRun (periodic command telling the DA to run) and accEvent (command telling the DA to handle an event). As you will see later on, this DA is set up to run as often as possible so that the mouse position coordinates appear to be updated continuously in the window.

This routine starts off by obtaining the window pointer from the device control entry and parsing the command (CSCode) sent to it. If it is a run command (accRun) then the new mouse position is displayed (by calling the routine dspMousePos). If it is the event command (accEvent) then the doEvent routine is called.

The doEvent routine handles 4 types of events - keyDown, autoKey, updateEvt, and activateEvt. The updateEvt will re-draw the coordinates and the window name. The activateEvt only re-draws the coordinates. The keyDown and autoKey events do most of the work in this code. When either of these events occur, a string is allocated, the coordinates and window name placed into the string (with the Munger ROM call), and moved to the clipboard.

Why did I append perfectly good strings into another string? I'm lazy I guess (plus the string is temporarily allocated off the heap and is released immediately). Notice that if the Cut or Copy keys are capitals (the CapsLock key is down) then the current TEXT contents of the clipboard are placed in the string. This allows the user to "append" coordinates together as previously described.

The dspMousePos routine first gets the current coordinates of the mouse. If the mouse has moved from the last time this routine was called, then processing continues, otherwise this routine just returns. This keeps down the "flicker" of the display, since the window is only updated when the mouse moves. It also keeps the DA from being a CPU hog.

Next, the name of the window the mouse is currently over is retrieved. If it is a different window than the last time, the new name is displayed (by the routine dspWindowTitle).

If the mouse is not on the desktop, then the local coordinates must be recomputed. GetMouse gives the mouse in local coordinates of the active window, not the window the mouse is currently over (which may be inactive or even invisible). Hence, the local coordinates must be recomputed with respect to the window the mouse is over. The rest of this routine is straightforward.

The coordinates are converted to strings, the "h" and "v" characters are appended to them, and these strings are displayed right justified in the window. Next, the four "Fat Bit" rectangles are displayed. Notice that 24 pixels surrounding the cursor in the horizontal direction and 16 pixels surrounding the cursor in the vertical direction are displayed (using CopyBits) in the window.

The dspWindowTitle routine first determines if the window passed to it is the desktop or a real window. If it is a real window, then its name is retrieved. Otherwise the name "DeskTop" is used. It then displays this name center justified in the DA window. It also adds a carriage return ('\n') to the name so that when the name is Cut or Copied to the clipboard, the coordinates will be on the next line (like in the window).

The drawWindow routine just draws the "static" portion of the window. This includes the "G" and "L" characters, the horizontal dividing lines, and the gray "crosshairs".

Consulair's DeskMaker

Now all of you desk accessory veterans are saying - "this stuff will never work, look at all of the global variables this guy has in a DA". Well, an application called DeskMaker by Consulair (included with their Mac C development system) takes alot of the headache out of writing DA's. After talking with Bill Duvall, he informed me that the way DeskMaker works is that it takes all of the global variables (referenced off of A4 by the #Options R=4 line) and makes them part of the DRVR resource (he appends them to the end of the code). This allows them to be global and still be accessed by the code in the DA. Of course, I didn't call him until I had already stayed up all night allocating my globals from the heap and accessing them through a handle. Oh well, it wasn't the first time I threw out code, and it won't be the last.

In addition to this, DeskMaker takes commands from a ".desk" text file to set up the DA's flags and header constants they require. You can turn any flag on or off, set up the other constants (like drvrDelay, drvrMask, etc.), and specify the names of the standard routines (Open, Close, Control, etc.) He has also added another command "Test" which allows you temporarily install the DA in the system menu to try it out. This is nice since you do not have to use Font/DA Mover or any of the other applications/DA's that run DA's from a file.

The "MousePos.Desk" listing shows the commands sent to DeskMaker for this DA. First, the filename, map, and name of the DA is set up. Next, the names of the 5 routines are defined. Finally, the drvrEMask, drvrDelay, and drvrFlags are set up. This DA was given the ID of 22 and the test flag was set to allow debugging. Since most of the C compilers handle DAs differently, this information should allow you to recreate this DA on other compilers.

MousePos.c Lisiting

/*************************************************************

  MousePos.c

     This is a desk accessory that shows three things about the position 
of the mouse cursor -

     - Name of the window the cursor is currently over
     - Local and global coordinates of the cursor
     - "Fat Bits" display of a rectangle around the cursor

      It also allows the user to Copy or Cut the window name and the 
local & global coordinates to the clipboard (CapsLock-Copy or CapsLock-Cut 
will append the coordinates to the clipboard).

 Written by: Rick Flott                           Mac C (Consulair) V 
4.5
*************************************************************/

#Options R=4 L=500 F=8000 Z Q=0 O=200

#include "MacCDefs.h"// Mac ROM data structure def's
#include "Events.h"
#include "Window.h"
#include "Font.h"
#include "TextEdit.h"
#include "Osmisc.h"
#include "Osio.h"
#include "Desk.h"

/*----------------------------------------------------------------
    Global Data
-----------------------------------------------------------------*/

/* ------ Constants ----- */

#define FALSE 0
#define TRUE  0xFF

/* ------- Types ------- */

typedef struct    // 6 char strings for the coord's
 {
 char count;
 char s[6];
 } Str6;

/* ---- Rectangles ---- */

Rect titleRect      = {  0,  0, 10,100},   // Window title rect
     localStrRect   = { 11,  1, 21,  6},
     localHRect     = { 11,  6, 21, 49},     // Local horiz coord's rect
     localVRect     = { 11, 52, 21, 94},   // Local vert  coord's rect
     globalStrRect  = { 21,  1, 31,  6},
     globalHRect    = { 21,  6, 31, 49},   // Global horiz coord's rect
     globalVRect    = { 21, 52, 31, 94},  // Global vert  coord's rect

     fBTopLeftRect  = { 32,  0, 64, 48}, // "Fat Bits" rect's
     fBBotLeftRect  = { 68,  0,100, 48},
     fBTopRightRect = { 32, 52, 64,100},
     fBBotRightRect = { 68, 52,100,100},

     windowRect     = { 50,  5,150,105}; // DA window rect

/* ----- Strings ------ */

char   deskTopTitle[] = {"\pDeskTop"}; // Constant desktop str

Str6   localVStr,  localHStr, // Local coord strings
       globalVStr, globalHStr;// Global coord strings

Str255 windowT;    // Window name string

/* --- Global Var's --- */

WindowPtr oldFrontWindow = 0; // Last front window ptr
Point     oldPt = {0,0};   // Last position of mouse

struct QDVar *getQD();


/*------------------------------------------------------------------------
    main()     (Open routine)

      The Open routine opens the desk accessory window and intializes 
any global data before the desk accessory is used.
-------------------------------------------------------------*/

int main(parameterBlock,DeviceControlEntry)
 CntrlParam       *parameterBlock;
 DeviceControl *DeviceControlEntry;
 {
 WindowPtr windowPtr;
 GrafPtr port;

 if ((windowPtr = DeviceControlEntry->dCtlWindow) == 0)
 {
 GetPort(&port); // Preserve appl window
    // Open DA window
 windowPtr = NewWindow(0, &windowRect,
 "\pMouse Pos",0,
 rDocProc, -1, 1, 0);
 if (windowPtr == 0)
      return(-1);

   SetPort(windowPtr);       // Use this new window

   // Set it as a system window
   ((WindowPeek)windowPtr)->windowKind =     
                                                  DeviceControlEntry->dCtlRefNum;

  // Save DA window ptr
   DeviceControlEntry->dCtlWindow=windowPtr;

   TextFont(monaco);    // Set up DA font
   TextSize(9);

   drawWindow();   // Draw static portion of window

   SetPort(port);   // Restore application window
   }

 return 0;

 } // end main()

/*----------------------------------------------------------------
    Close()

      The Close routine disposes of the desk accessory window and any 
data allocated on the heap.
--------------------------------------------------------------*/

int Close(parameterBlock,DeviceControlEntry)
 CntrlParam       *parameterBlock;
 DeviceControl *DeviceControlEntry;
 {
 WindowPtr windowPtr;
 // Get DA window ptr
 windowPtr = DeviceControlEntry->dCtlWindow; 

 DisposeWindow(windowPtr);   // Release DA window
 DeviceControlEntry->dCtlWindow = 0;

 return 0;

 } // end Close()

/*--------------------------------------------------------------
   Prime()

      This desk accessory does not use a Prime routine.
----------------------------------------------------------------*/

Prime(parameterBlock,DeviceControlEntry)
 CntrlParam       *parameterBlock;
 DeviceControl *DeviceControlEntry;
 {
 }

/*--------------------------------------------------------------
   Status(parameterBlock,DeviceControlEntry)

      This desk accessory does not use a Status routine.
---------------------------------------------------------------*/

Status(parameterBlock,DeviceControlEntry)
 CntrlParam       *parameterBlock;
 DeviceControl *DeviceControlEntry;
 {
 }

/*----------------------------------------------------------------
    Control()

      The Control routine parses the desk accessory command sent from 
the system and routes the data to the proper routine. The commands currently 
used are -

 accRun - Display the mouse position.
 accEvent - Handle Cut and Copy menu commands.

----------------------------------------------------------------*/

Control(parameterBlock,DeviceControlEntry)
 CntrlParam       *parameterBlock;
 DeviceControl *DeviceControlEntry;
 {
 GrafPtr port;
 WindowPtr windowPtr;
 // Get DA window ptr
 windowPtr = DeviceControlEntry->dCtlWindow; 

 GetPort(&port); // Preserve application window
 SetPort(windowPtr);    // Use DA window

 switch (parameterBlock->CSCode) // What cmd was sent?
 {
 case accRun:      // cmd = RUN
 dspMousePos(windowPtr);      // Display new  position
 break;
 case accEvent:   // cmd = HANDLE EVENT
 doEvent(parameterBlock->csp.event,windowPtr);
 break;
 } // end switch

 SetPort(port);   // Restore appl window

  } // end Control()


/*----------------------------------------------------------------
    doEvent()

      This routine parses the event sent from the system. The events 
currently used are -

 keyDown, autoKey  - Cut or Copy the window name &                   
                                                  mouse coord's to clipboard.

 updateEvt         - Redraw the entire desk acc window.

 activateEvt       - Redraw the only the mouse coord's.

--------------------------------------------------------------*/

doEvent(event,windowPtr)
 EventRecord *event;
 WindowPtr    windowPtr;
 {
 Handle strHandle;
 Ptr    strPtr;
 int    scrapOffset;
 long   offset = 0;

 switch (event->what)// Which event occurred?
 {
 case keyDown:
 case autoKey:   // Event = KEY PUSH
 if ((event->modifiers&cmdKey))      // Was it a cmd key?
 {
 strHandle = (Handle)NewHandle(0); // Allocate a string

 // Only allow Cut,Copy
 switch ((char)(event->message))
 {
 case 'C':         // If Shift/CapsLock, copy previous clip
 case 'X':
 offset = GetScrap(strHandle,
  'TEXT',&scrapOffset);
 case 'c':
 case 'x':
 if (offset < 0)   // Was there a scrap error?
 {
 SysBeep(2);// Y - return
 break;
 }

 if (ZeroScrap())// Clear the clipboard
 {
 SysBeep(2);
 break;
 }

        // Grow string to place clipboard stuff in

   SetHandleSize(strHandle,offset+
 (sizeof windowT)+
 (sizeof localHStr)+
 (sizeof localVStr)+
 (sizeof globalHStr)+
 (sizeof globalVStr));

        // Place window name, local, global coord's into string

        offset = Munger(strHandle, offset,0,0, windowT.s,      
 (long) windowT.count);
           offset = Munger(strHandle, offset,0,0, localHStr.s, 
 (long) localHStr.count);
        offset = Munger(strHandle, offset,0,0, localVStr.s,    
 (long) localVStr.count);
        offset = Munger(strHandle, offset,0,0, globalHStr.s,
 (long) globalHStr.count);
        offset = Munger(strHandle,offset,0,0, globalVStr.s,
 (long) globalVStr.count);

        HLock(strHandle); // Lock the string down

        strPtr = (Ptr)*strHandle;
        // Put string into clipboard
        if (PutScrap((long)offset,'TEXT',strPtr))
 SysBeep(20);

   HUnlock(strHandle);  // Unlock the string
   break;

        default: // Beep on other cmd keys
        SysBeep(2);
    break;

 } // end switch

 DisposHandle(strHandle); // Release the string
   } // end if

   return;

 case updateEvt: // Event = UPDATE EVENT
 SetPort(windowPtr);  // Use DA window
 BeginUpdate(windowPtr);
 drawWindow();      // Redraw the window
 // Display  new window title
 dspWindowTitle(oldFrontWindow); 
 EndUpdate(windowPtr);
 return;

 case activateEvt: // Event = ACTIVATE EVENT
 dspMousePos(windowPtr);   // Display  new mouse pos
 return;

    } // end switch
  } // end doEvent()

/*-----------------------------------------------------------
   dspMousePos()

      This routine displays the position of the mouse. It displays the 
following information -

 - Local and global coordinates of the cursor
 - "Fat Bits" display of a rectangle around the cursor

------------------------------------------------------------*/

dspMousePos(windowPtr)
  WindowPtr windowPtr;
  {
  Rect      cursorRect;
  WindowPtr mouseWindow;
  short     windowCode;
  struct    QDVar *myQD;  // Place for copy of QD pointer
  Point     localPt,globalPt;

  myQD = getQD();// Get a copy of QD pointer

  GetMouse(&localPt);// Get the new mouse position
  globalPt = localPt;
  LocalToGlobal(&globalPt); // Convert it to global coord's

  if (!EqualPt(&globalPt,&oldPt))  // Has the mouse moved?
 {
    oldPt = globalPt;// Y - remember where it now is

  // Determine the window the mouse is now in
    windowCode = FindWindow(&globalPt, 
   &mouseWindow);

 // Is mouse in a different window?
    if (oldFrontWindow != mouseWindow)
            // Y - Display  title of new window
      dspWindowTitle(oldFrontWindow = mouseWindow);

    if (mouseWindow) // Is the mouse on the Desktop?
      { // N - get, display  local coord's
 // Get local coord's of window mouse is in
      SetPort(mouseWindow);
      localPt = globalPt;
      GlobalToLocal(&localPt);
           // Convert local coord's to strings
      NumToString(localPt.h,&localHStr);
      NumToString(localPt.v,&localVStr);

      localHStr.s[localHStr.count++]='h';    // Add in 'h' and 'v'
      localVStr.s[localVStr.count++]='v';
      localVStr.s[localVStr.count++]='\n';   // Add CR
      }
    else    // Y - don't display local coord's when on desktop
      localHStr.count=localVStr.count=0;

    SetPort(windowPtr);      // Draw in desk acc window
 // Convert global coord's to strings
    NumToString(globalPt.h,&globalHStr);
    NumToString(globalPt.v,&globalVStr);

    globalHStr.s[globalHStr.count++]='h';    // Add in 'h' and 'v'
    globalVStr.s[globalVStr.count++]='v';
    globalVStr.s[globalVStr.count++]='\n';   // Add CR

 // Display global coord's
    TextBox(globalHStr.s,globalHStr.count,
                      &globalHRect,-1);
    TextBox(globalVStr.s,globalVStr.count,
                      &globalVRect,-1);
 // Display local coord's
    TextBox(localHStr.s,localHStr.count,     
            &localHRect,-1);
    TextBox(localVStr.s,localVStr.count,
            &localVRect,-1);


    SetRect(&cursorRect,  // Set up top left "Fat Bits" rect
                      globalPt.h-12,globalPt.v-8,
           globalPt.h, globalPt.v);
    CopyBits(&myQD->screenBits, // Display  top left "Fat Bits"
                       &windowPtr->portBits,
    &cursorRect,&fBTopLeftRect,srcCopy,0);


    SetRect(&cursorRect,  // Set up bottom left "Fat Bits" rect
                     globalPt.h-12,globalPt.v,
  globalPt.h, globalPt.v+8);
    CopyBits(&myQD->screenBits,    // Display bot left "Fat Bits"
             &windowPtr->portBits,
    &cursorRect,&fBBotLeftRect,srcCopy,0);

    SetRect(&cursorRect,  // Set up bottom right "Fat Bits" rect
                      globalPt.h, globalPt.v,
   globalPt.h+12,globalPt.v+8);
    CopyBits(&myQD->screenBits,  // Display bot right "Fat Bits"
                        &windowPtr->portBits,
 &cursorRect,&fBBotRightRect,srcCopy,0);


    SetRect(&cursorRect,  // Set up top right "Fat Bits" rect
                     globalPt.h, globalPt.v-8,
 globalPt.h+12,globalPt.v);
    CopyBits(&myQD->screenBits,  // Display top right "Fat Bits"
                        &windowPtr->portBits,
 &cursorRect,&fBTopRightRect,srcCopy,0);

    } // endif
  } // end dspMousePos()

/*----------------------------------------------------------------
   dspWindowTitle()

      This routine displays the name of the window passed to it in the 
window title rectangle.

---------------------------------------------------------------*/
dspWindowTitle(windowPtr)
  WindowPtr windowPtr;
  {
  if (windowPtr) // Is the mouse in a real window?
  // Y - display  window's name
    GetWTitle(windowPtr,&windowT);
  else   // N - display the desktop name
    BlockMove(&deskTopTitle[0],&windowT,deskTopTitle[0]+1);

  TextBox(windowT.s,windowT.count,&titleRect,1);
  windowT.s[windowT.count++] = '\n'; // Add CR

 } // end dspWindowTitle()

/*----------------------------------------------------------------------
  drawWindow()

 This routine draws the "static" portion of the window.

  ----------------------------------------------------------------------*/
drawWindow()
  {
  struct    QDVar *myQD;  // Place for copy of QD pointer

  myQD = getQD();  // Get a copy of QD pointer

  MoveTo(globalStrRect.left,// Draw "G"
                   globalStrRect.bottom - 1 );
  DrawChar('G');

 MoveTo(localStrRect.left,  // Draw "L"
                   localStrRect.bottom - 1);
  DrawChar('L');

  MoveTo(0,titleRect.bottom);  // Draw the horiz dividing lines
  Line(titleRect.right,0);
  MoveTo(0,globalStrRect.bottom);
  Line(titleRect.right,0);

  PenSize(4,4);
  PenPat(&myQD->gray);

  MoveTo(fBTopLeftRect.right,    // Draw crosshairs
                   fBTopLeftRect.bottom);
  LineTo(fBTopRightRect.right,fBTopRightRect.bottom);

  MoveTo(fBTopLeftRect.right,
                   fBTopLeftRect.bottom);
  LineTo(fBBotLeftRect.right,fBBotLeftRect.bottom);

  MoveTo(fBTopLeftRect.right,
                   fBTopLeftRect.bottom);
  LineTo(fBTopLeftRect.left,fBTopLeftRect.bottom);

  MoveTo(fBTopLeftRect.right,
                   fBTopLeftRect.bottom);
  LineTo(fBTopLeftRect.right,fBTopLeftRect.top);

  PenNormal();

  } // end drawWindow()

/*--------------------------------------------------------------
      getQD()

      This routine returns the pointer used by Quikdraw to point to its 
global data.

-------------------------------------------------------------*/
 {
  #asm

grafSizeEQU $CA

  MOVE.L0(A5),A0
  SUB.L #grafSize,A0

  #endasm
  } // end getQD()

/*-------------------------------------------------------------
      NumToString()  (Package glue routine)

---------------------------------------------------------------*/

NumToString(theNum,theString)
  long         theNum;
  struct PStr *theString;

  {
  #asm
 MOVE.L D1,A0    ; theString
 MOVE   #0,-(SP) ; NumToString selector
 DC.W   $A9EE    ; PACK7
  #endasm
  }

MousePos.link Listing

/NoAnimate
/Output MousePos
/Type 'DFIL' 'DMOV'

MousePos

$

MousePos.desk Listing

File MousePos

Map MousePos.map

Name "Mouse Position"

Open main

Close close

Control control

Status status

Prime prime

EventMask 362
Delay 0

+ Periodic
+ Control
+ Status

DeskID 22

+ Test
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Box Sync 4.0.6567 - Online synchronizati...
Box Sync gives you a hard-drive in the Cloud for online storage. Note: You must first sign up to use Box. What if the files you need are on your laptop -- but you're on the road with your iPhone? No... Read more
Carbon Copy Cloner 4.1.4 - Easy-to-use b...
Carbon Copy Cloner backups are better than ordinary backups. Suppose the unthinkable happens while you're under deadline to finish a project: your Mac is unresponsive and all you hear is an ominous,... Read more
OmniGraffle Pro 6.3.1 - Create diagrams,...
OmniGraffle Pro helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use... Read more
Monosnap 3.1.2 - Versatile screenshot ut...
Monosnap lets you capture screenshots, share files, and record video and .gifs! Capture: Capture full screen, just part of the screen, or a selected window Make your crop area pixel perfect with... Read more
Alfred 2.7.2 - Quick launcher for apps a...
Alfred is an award-winning productivity application for OS X. Alfred saves you time when you search for files online or on your Mac. Be more productive with hotkeys, keywords, and file actions at... Read more
Microsoft Remote Desktop 8.0.19 - Connec...
With Microsoft Remote Desktop, you can connect to a remote PC and your work resources from almost anywhere. Experience the power of Windows with RemoteFX in a Remote Desktop client designed to help... Read more
OmniGraffle 6.3 - Create diagrams, flow...
OmniGraffle helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use Graffle to... Read more
PDFKey Pro 4.3.2 - Edit and print passwo...
PDFKey Pro can unlock PDF documents protected for printing and copying when you've forgotten your password. It can now also protect your PDF files with a password to prevent unauthorized access and/... Read more
Ableton Live 9.2.2 - Record music using...
Ableton Live lets you create and record music on your Mac. Use digital instruments, pre-recorded sounds, and sampled loops to arrange, produce, and perform your music like never before. Ableton Live... Read more
Macs Fan Control 1.3.1.0 - Monitor and c...
Macs Fan Control allows you to monitor and control almost any aspect of your computer's fans, with support for controlling fan speed, temperature sensors pane, menu-bar icon, and autostart with... Read more

ReBoard: Revolutionary Keyboard (Utilit...
ReBoard: Revolutionary Keyboard 1.0 Device: iOS Universal Category: Utilities Price: $1.99, Version: 1.0 (iTunes) Description: Do everything within the keyboard without switching apps! If you are in WhatsApp, how do you schedule a... | Read more »
Tiny Empire (Games)
Tiny Empire 1.1.3 Device: iOS Universal Category: Games Price: $2.99, Version: 1.1.3 (iTunes) Description: Launch cannonballs and blow tiny orcs into thousands of pieces in this intuitive fantasy-themed puzzle shooter! Embark on an... | Read more »
Astropad Mini (Productivity)
Astropad Mini 1.0 Device: iOS iPhone Category: Productivity Price: $4.99, Version: 1.0 (iTunes) Description: *** 50% off introductory price! ​*** Get the high-end experience of a Wacom tablet at a fraction of the price with Astropad... | Read more »
Emo Chorus (Music)
Emo Chorus 1.0.0 Device: iOS Universal Category: Music Price: $1.99, Version: 1.0.0 (iTunes) Description: Realistic Choir simulator ranging from simple Chorus emulation to full ensemble Choir with 128 members. ### introductory offer... | Read more »
Forest Spirit (Games)
Forest Spirit 1.0.5 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.5 (iTunes) Description: | Read more »
Ski Safari 2 (Games)
Ski Safari 2 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: The world's most fantastical, fun, family-friendly skiing game is back and better than ever! Play as Sven's sister Evana, share... | Read more »
Lara Croft GO (Games)
Lara Croft GO 1.0.47768 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.47768 (iTunes) Description: Lara Croft GO is a turn based puzzle-adventure set in a long-forgotten world. Explore the ruins of an ancient... | Read more »
Whispering Willows (Games)
Whispering Willows 1.23 Device: iOS Universal Category: Games Price: $4.99, Version: 1.23 (iTunes) Description: **LAUNCH SALE 50% OFF** - Whispering Willows is on sale for 50% off ($4.99) until September 9th. | Read more »
Calvino Noir (Games)
Calvino Noir 1.1 Device: iOS iPhone Category: Games Price: $3.99, Version: 1.1 (iTunes) Description: The film noir stealth game. Calvino Noir is the exploratory, sneaking adventure through the 1930s European criminal underworld.... | Read more »
Angel Sword (Games)
Angel Sword 1.0 Device: iOS Universal Category: Games Price: $6.99, Version: 1.0 (iTunes) Description: Prepare to adventure in the most epic full scale multiplayer 3D RPG for mobile! Experience amazing detailed graphics in full HD.... | Read more »

Price Scanner via MacPrices.net

Apple and Cisco Partner to Deliver Fast-Lane...
Apple and Cisco have announced a partnership to create a “fast lane” for iOS business users by optimizing Cisco networks for iOS devices and apps. The alliance integrates iPhone with Cisco enterprise... Read more
Apple offering refurbished 2015 13-inch Retin...
The Apple Store is offering Apple Certified Refurbished 2015 13″ Retina MacBook Pros for up to $270 (15%) off the cost of new models. An Apple one-year warranty is included with each model, and... Read more
Apple refurbished 2015 MacBook Airs available...
The Apple Store has Apple Certified Refurbished 2015 11″ and 13″ MacBook Airs (the latest models), available for up to $180 off the cost of new models. An Apple one-year warranty is included with... Read more
21-inch iMacs on sale for up to $120 off MSRP
B&H Photo has 21″ iMacs on sale for up to $120 off MSRP including free shipping plus NY sales tax only: - 21″ 1.4GHz iMac: $999.99 $100 off - 21″ 2.7GHz iMac: $1199.99 $100 off - 21″ 2.9GHz iMac... Read more
5K iMacs on sale for up to $150 off MSRP, fre...
B&H Photo has the 27″ 3.3GHz 5K iMac on sale for $1899.99 including free shipping plus NY tax only. Their price is $100 off MSRP. They have the 27″ 3.5GHz 5K iMac on sale for $2149.99 $2199.99, $... Read more
1.4GHz Mac mini, refurbished, available for $...
The Apple Store has Apple Certified Refurbished 1.4GHz Mac minis available for $419. Apple’s one-year warranty is included, and shipping is free. Their price is $80 off MSRP, and it’s the lowest... Read more
iPad Air 2 on sale for up to $100 off MSRP
Best Buy has iPad Air 2s on sale for up to $100 off MSRP on their online store for a limited time. Choose free shipping or free local store pickup (if available). Sale prices available for online... Read more
MacBook Airs on sale for $100 off MSRP
Best Buy has MacBook Airs on sale for $100 off MSRP on their online store. Choose free shipping or free local store pickup (if available). Sale prices for online orders only, in-store prices may vary... Read more
Big Grips Lift Handle For iPad Air and iPad A...
KEM Ventures, Inc. which pioneered the extra-large, super-protective iPad case market with the introduction of Big Grips Frame and Stand in 2011, is launching Big Grips Lift featuring a new super-... Read more
Samsung Launches Galaxy Tab S2, Its Most Powe...
Samsung Electronics America, Inc. has announced the U.S. release of the Galaxy Tab S2, its thinnest, lightest, ultra-fast tablet. Blending form and function, elegant design and multitasking power,... Read more

Jobs Board

*Apple* Evangelist - JAMF Software (United S...
The Apple Evangelist is responsible for building and cultivating strategic relationships with Apple 's small and mid-market business development field teams. This Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Desktop Analyst - KDS Staffing (Unit...
…field and consistent professional recruiting achievement. Job Description: Title: Apple Desktop AnalystPosition Type: Full-time PermanentLocation: White Plains, NYHot Read more
*Apple* Systems Engineer (Mclean, VA and NYC...
Title: Apple Systems Engineer (Mclean, VA and NYC) Location: United States-New York-New York-200 Park Ave (22005) Other Locations: United States-Virginia-Vienna-Towers Read more
*Apple* Systems Engineer (Mclean, VA and NYC...
…Assist in providing strategic direction and technical leadership within the Apple portfolio, including desktops, laptops, and printing environment. This person will Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.