TweetFollow Us on Twitter

Menu Hide, Seek
Volume Number:7
Issue Number:2
Column Tag:Pascal Procedures

Related Info: Menu Manager Script Manager Window Manager

Menu Bar Hide & Seek

By D. Grant Leeper, Buena Park, CA

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

[Grant has been programming the Mac since the original 128K model back in 1984. He is currently working on a 3D graphics library for MacApp and a set of HyperCard XFCNs that allow HyperCard users to access the Script Manager 2.0 extended date, geographic location, and number formatting facilities. He is also available for contract programming work and can be contacted on CompuServe at 70157,1670 or on AppleLink at D0428.]

The Disclaimer

The techniques described in this article should work on any current Macintosh computer with the 128K ROMs or newer (512KE, Plus, SE series, II series) using system 6.0.4 or less, with or without MultiFinder running. However several of the steps described violate Apple’s rules for future compatibility and could break in the future. Take this into account when implementing these techniques. These techniques are not supported by Apple, if they break don’t blame Apple (or me), you were warned!

Now, having said all that, on with the story.

The Introduction

So, in spite of all you’ve heard about future compatibility you have a case where you just absolutely, positively have to hide the menu bar in your application. This is the story of how you can do it.

The accompanying Pascal unit which I have called ShowHideMBar provides the basic tools required to hide and redisplay the menu bar. When the menu bar is hidden command key equivalents to items in the menu bar will still work. In addition, you can detect a mouse click in the hidden menu bar and react to it by displaying the menu bar, or just the menus, long enough to issue a single menu command.

I have also provided a sample application to demonstrate the use of this unit. It is similar to sample applications provided by Apple’s own MacDTS and so it is rather sparsely commented. For the most part the only comments in the code are those that apply to hiding the menu bar. It is probably simpler for readers to apply the techniques I describe to an existing application of their own rather than typing in the entire example.

The Warning

A warning is appropriate here. Under MultiFinder, it is an extremely bad idea to allow an application to become suspended or worse to quit while the menu bar is hidden. If an application gets suspended without redisplaying the menu bar the new foreground application will not have a menu bar visible. The user could end up trapped in an application with no menu bar and no way out but to quit or reboot. The situation is worse if an application exits without redisplaying the menu bar. The unit ShowHideMBar saves the menu bar height as it existed before hiding the menu bar. It uses this to restore the menu bar and desktop when the menu bar is to be made visible again. If the application exits this information is lost.

Note that this warning does not apply to what Apple calls “minor switching” and “update switching” (Tech Note #180, revised June 1989). Minor switching is when a foreground application goes to sleep and background tasks receive null events to perform background processing. Null events do not affect the menu bar so this is not a problem. Update switching is when background applications get a chance to update their windows. Since the disappearance of the menu bar can make previously hidden portions of background windows visible as well as our own, we actually want this to happen.

Without MultiFinder the desktop is currently rebuilt when an application exits. But since there’s no approved way for an application to tell if MultiFinder is running it’s best to just assume it will be and code for it.

The sample application shows how to deal with this properly for a finished application. It is important to be careful though when debugging an application because the menu bar may not be visible when entering a debugger. For low level debuggers like MacsBug this means you don’t want to issue an exit to shell or restart the application command from the debugger if the menu bar is hidden. For high level debuggers like SADE which use menu bars of their own you will not be able to access the menu bar with the mouse if you enter it with the menu bar hidden.

The Tools

There are five public routines defined in this unit, they are declared as follows:

PROCEDURE HideMenuBar;

You call HideMenuBar when you want to make the menu bar invisible. You can call it as soon as you have done the standard toolbox initializations if you want the menu bar to be initially (or always) hidden. Or you can call it in response to a request from the user. Calling it with the menu bar already hidden will have no effect.

PROCEDURE ShowMenuBar;

Call ShowMenuBar to display the menu bar if it is hidden, usually in response to a request from the user, but also when suspending or quitting. Calling it with the menu bar already showing will have no effect.

FUNCTION  MenuBarVisible: BOOLEAN;

This function allows the application to determine if the menu bar is currently visible.

FUNCTION  PtInMenuBar(pt: Point): BOOLEAN;

Call this to find out if a point would be in the menu bar if it were visible. If FindWindow returns inDesk and this function returns TRUE you could display the menu bar long enough for the user to issue a single menu command.

FUNCTION  HiddenMenuSelect(startPt: Point): LONGINT;

This routine is equivalent to the toolbox trap MenuSelect except that it can be called when the menu bar is hidden. If in response to a mouse down event FindWindow returns inDesk and PtInMenuBar returns TRUE, you can call this function to allow the user to issue a menu command. It does not make the menu bar visible but only draws individual menus as they are selected. If you want to display the entire menu bar at this time call ShowMenuBar first then HiddenMenuSelect followed by HideMenuBar.

The Way It All Works

The Mac keeps track of the desktop and the menu bar by using low-memory global variables. In order to hide the menu bar we have to modify some of these variables (which are usually considered read only at best, this is why these techniques are subject to breaking. Remember these techniques break some of the rules! Use them cautiously.

The variables we are concerned with are MBarHeight and GrayRgn. MBarHeight is the height, in pixels, of the menu bar at the top of the main screen. GrayRgn is a handle to a region that defines the desktop. If there are multiple monitors in use on a Mac the desktop will include them all. GrayRgn includes all of the normally gray area on an empty desktop. It does not include the menu bar or the area outside the rounded corners at the four corners of the desktop’s bounding box .

In order to hide the menu bar we first set the low-memory variable MBarHeight to 0 while saving its existing value for when we want to make it visible again. Next we add the area occupied by the menu to GrayRgn. Then we repaint the menu bar as part of the desktop, generating update events for any windows that intersect the menu bar. And finally, again for any windows that intersect the menu bar, we add the overlap with the menu bar to their visRgn fields. The first two steps are easy, the last two are done for us by calling the two low-level window manager routines PaintBehind and CalcVisBehind which I’ll describe shortly.

In order to redisplay a hidden menu bar we follow a similar procedure. First we restore the variable MBarHeight to its previous value. Then we remove the area occupied by the menu bar from GrayRgn. Next we remove the area that overlaps the menu bar from the visRgn fields of any windows that intersect the menu bar, again using CalcVisBehind. And, finally we redraw the menu bar.

Accessing MBarHeight and GrayRgn is simple. On machines with the 128K or larger ROMs the menu bar height is stored as a word at low-memory location $0BAA. The variable MBarHeight is not present on machines with the original 64K ROM. On these machines the menu bar height is always 20 pixels and cannot be changed. We can’t hide the menu bar on old ROM machines. GrayRgn is stored in the long word at location $09EE on all Macintoshes.

The Script Manager provides the following Pascal inline function to read the menu bar height:

FUNCTION  GetMBarHeight: INTEGER;
 INLINE $3EB8, $0BAA;
 { MOVE MBarHeight,(SP) }

The Window Manager provides a similar function for getting the contents of GrayRgn:

FUNCTION  GetGrayRgn: RgnHandle;
 INLINE $2EB8, $09EE;
 { MOVE.L GrayRgn,(SP) }

We will use the following inline function to change the menu bar height (writing to low memory global variables is bad programming practice, we do it here only because there is no other way):

PROCEDURE SetMBarHeight(height: INTEGER);
 INLINE $31DF, $0BAA;
 { MOVE (SP)+, MBarHeight }

We don’t need a SetGrayRgn routine, since it’s a handle we can manipulate it in place where necessary. Modifying GrayRgn is also bad programming, again we do it only because there’s no other way.

I provide the routine GetMBarRgn to determine the area to add to and subtract from GrayRgn when we hide and show the menu bar respectively. The menu bar is always drawn with both of its top corners rounded. When we expand GrayRgn, however, we want the added area to be contiguous with the existing GrayRgn. For this reason we will only round a corner of the menu bar region if that corner coincides with a corner of GrayRgn’s bounding box. This will look better on systems with multiple monitors. It’s possible for example to have two monitors with one stacked on top of the another. The menu bar can be at the top of the bottom monitor, dividing the total screen area in two. When we remove the menu bar we don’t want to leave the menu bar’s round corners poking into the middle of the screen.

GetMBarRgn starts by unioning the menu bar rectangle (the top MBarHeight lines of screenBits.bounds) with the bounding box of GrayRgn. This is always the total screen area no matter how many monitors are in use. It then creates a round cornered region out of this and intersects it with the menu bar rectangle. This intersection is the region we will add to or subtract from GrayRgn.

After setting the menu bar height to zero and expanding the desktop region it is necessary to redraw the menu bar as part of the desktop, and to add any window overlap with the menu bar to the visRgn fields of the affected windows. For this we use the low-level Window Manager traps PaintBehind and CalcVisBehind. These traps are declared as follows:

PaintBehind(startWindow: WindowPeek; clobberedRgn: RgnHandle);

CalcVisBehind(startWindow: WindowPeek; clobberedRgn: RgnHandle);

PaintBehind redraws the intersection of clobberedRgn and the desktop, including the window frames of startWindow and all the windows behind it, and for any of these windows whose content regions intersect clobberedRgn it generates the needed update events.

CalcVisBehind recalculates the visRgn fields of all windows on the desktop, behind and including startWindow, that intersect clobberedRgn.

When we call either of these traps we pass them the result of FrontWindow for startWindow and the result of GetMBarRgn for clobberedRgn. We call these two traps in sequence to reconstruct the desktop after it has been expanded. We call CalcVisBehind followed by DrawMenuBar to reconstruct the desktop after it has been reduced.

The Way You Use It

You only need to make a few parts of your application “menu bar aware.”

If your application is to be compatible with old ROM machines (64K ROM or Macintosh XL) make all calls to ShowHideMBar routines conditional on the presence of the 128K ROM. Otherwise just check for it once in your initialization routine and exit gracefully if it is not available.

Call HideMenuBar in your initialize routine to have the menu bar initially hidden. Call it after initializing the toolbox and checking that the 128K ROM or newer is available.

Anywhere you call ExitToShell first call ShowMenuBar. If this is in a failure handler that could be called because the 128K ROM is unavailable check for the ROM first.

Call HideMenuBar and ShowMenuBar in response to whatever user commands you define for hiding and showing the menu bar. A good suggestion is to use command-space as a toggle command. This is what HyperCard uses and your users will probably be familiar with it.

To determine if the menu bar is currently visible call MenuBarVisible.

Support MultiFinder suspend/resume events. In response to a suspend message save the result of MenuBarVisible in a global variable and call ShowMenuBar. In response to a resume event check this global variable and call HideMenuBar if it is FALSE. If for some reason you are not supporting suspend/resume events then you should respond to deactivate/activate events in this manner instead. But, this will cause the (usually undesirable) side effect of briefly displaying the hidden menu bar whenever a different one of your application’s windows is activated.

You can allow the user to make menu selections even when the menu bar is hidden. To do this call PtInMenuBar with the global coordinates of the mouse in response to a mouse down event when FindWindow returns inDesk. Checking for inDesk avoids confusing mouse downs intended for windows with those intended for the menu bar. If it returns TRUE then call HiddenMenuSelect, optionally bracket by calls to ShowMenuBar and HideMenuBar. Calling the show and hide routines here causes the entire menu bar to be made temporarily visible while the user makes a menu selection. If you do not call these then the menu bar will not be drawn, instead the individual menus will appear magically from nowhere as they are selected.

The Wrap-Up

Well that’s about it. It’s really much simpler to use than to write about. Just have a look at the source code and have fun.

Listing:  HideMenuBarExample.make

#HideMenuBarExample.make
#MPW 3.0 make file for menu bar hiding example
#Copyright © 1989 D. Grant Leeper.
#All rights reserved.
#Publication rights granted to MacTutor.

POptions =-r

srcs =  :Sources:
objs =  :Objects:

objects = {objs}HideMenuBarExample.p.o 
 {objs}ShowHideMBar.p.o

{objs} ƒ{srcs}

HideMenuBarExample.p.o ƒ  ShowHideMBar.p.o

HideMenuBarExample ƒƒ{objects}
 Link {objects} -o {Targ} 
 “{Libraries}”Runtime.o 
 “{Libraries}”Interface.o 
 “{PLibraries}”PasLib.o

HideMenuBarExample ƒƒ 
 {srcs}HideMenuBarExample.r
 Rez {srcs}HideMenuBarExample.r -a -o {Targ}
 DeRez {targ} -only vers > DeRez.out
 Rez DeRez.out -a -m 
 -o HideMenuBarExample.make
 Rez DeRez.out -a -m 
 -o {srcs}ShowHideMBar.p
 Rez DeRez.out -a -m 
 -o {srcs}HideMenuBarExample.p
 Rez DeRez.out -a -m 
 -o {srcs}HideMenuBarExample.r
 Rez DeRez.out -a -m 
 -o {objs}ShowHideMBar.p.o
 Rez DeRez.out -a -m 
 -o {objs}HideMenuBarExample.p.o
 Delete DeRez.out
Listing:  ShowHideMBar.p

{
ShowHideMBar.p
MPW 3.0 Pascal unit to hide the menu bar
Copyright © 1989 D. Grant Leeper.
All rights reserved.
Publication rights granted to MacTutor.

NOTE: The calling application is responsible for
insuring that the menu bar is left visible after
suspending and quitting!

CAUTION: This code violates the guidelines for
future compatibility, use it at your own risk.
Specifically it modifies the GrayRgn and
MBarHeight global variables, and paints and
manipulates the window manager port.
Also, since it modifies MBarHeight it requires
the 128K (or newer) ROMs.
}

UNIT ShowHideMBar;

INTERFACE

USES
 Types, QuickDraw, Events,
 Controls, Windows, Menus;

PROCEDURE HideMenuBar;

PROCEDURE ShowMenuBar;

FUNCTION  MenuBarVisible: BOOLEAN;

FUNCTION  PtInMenuBar(pt: Point): BOOLEAN;

FUNCTION  HiddenMenuSelect(startPt: Point): LONGINT;

IMPLEMENTATION

VAR
 gSavedMBarHeight: INTEGER;
(*
CONST
 GrayRgn =$09EE;
 MBarHeight =  $0BAA;

{ Defined in Windows.p }
FUNCTION  GetGrayRgn: RgnHandle;
 INLINE $2EB8, $09EE; { MOVE.L GrayRgn,(SP) }
*)
{ Defined in Script.p }
FUNCTION  GetMBarHeight: INTEGER;
 INLINE $3EB8, $0BAA; { MOVE MBarHeight,(SP) }

PROCEDURE SetMBarHeight(height: INTEGER);
 INLINE $31DF, $0BAA; { MOVE (SP)+,MBarHeight }

FUNCTION  GetWindowList: WindowPtr;
 INLINE $2EB8, $9D6; { MOVE.L WindowList,(SP) }

{$S ShowHideMBar}
FUNCTION  GetMBarRgn: RgnHandle;
 VAR
 r:Rect;
 worldRgn:RgnHandle;
 mBarRgn: RgnHandle;
 BEGIN
 { Compute worldRgn, the round cornered
   rectangle that bounds all screens }
 r := GetGrayRgn^^.rgnBBox;
 UnionRect(r, screenBits.bounds, r);
 worldRgn := NewRgn;
 OpenRgn;
 FrameRoundRect(r, 16, 16);
 CloseRgn(worldRgn);
 
 { Compute mBarRgn, the intersection
   of the menu bar’s rectangle with
   worldRgn. }
 r := screenBits.bounds;
 r.bottom := r.top + gSavedMBarHeight;
 mBarRgn := NewRgn;
 RectRgn(mBarRgn, r);
 SectRgn(worldRgn, mBarRgn, mBarRgn);
 
 DisposeRgn(worldRgn);
 GetMBarRgn := mBarRgn
 END; { GetMBarRgn }

{$S ShowHideMBar}
PROCEDURE HideMenuBar;
 VAR
 mBarHeight:INTEGER;
 grayRgn: RgnHandle;
 menuBarRgn:RgnHandle;
 startWindow:  WindowPeek;
 BEGIN
 mBarHeight := GetMBarHeight;
 IF mBarHeight <> 0 THEN
 BEGIN
 grayRgn := GetGrayRgn;
 { GSavedMBarHeight must be valid when calling GetMBarRgn }
 gSavedMBarHeight := mBarHeight;
 menuBarRgn := GetMBarRgn;
 SetMBarHeight(0);
 { Add menuBarRgn to GrayRgn. }
 UnionRgn(grayRgn, menuBarRgn, grayRgn);
 { Now tell the Window Manager that the
   desktop has expanded, so the area
   under the menu bar will get
   updated correctly.  We do this by
   calling two of the low-level
   Window Manager routines PaintBehind
   and CalcVisBehind. }
 startWindow := WindowPeek(GetWindowList);
 { PaintBehind redraws the desktop,
   including window frames, as made
   necessary by the removal of the menu
   bar.  It also generates the needed
   window update events. }
 PaintBehind(startWindow, menuBarRgn);
 { CalcVisBehind recalculates any window
   visRgns that need to be changed to
   allow for the removal of the menu bar. }
 CalcVisBehind(startWindow, menuBarRgn);
 DisposeRgn(menuBarRgn)
 END { IF }
 END; { HideMenuBar }

{$S ShowHideMBar}
PROCEDURE ShowMenuBar;
 VAR
 grayRgn: RgnHandle;
 menuBarRgn:RgnHandle;
 BEGIN
 IF GetMBarHeight = 0 THEN
 BEGIN
 grayRgn := GetGrayRgn;
 menuBarRgn := GetMBarRgn;
 SetMBarHeight(gSavedMBarHeight);
 { Remove menuBarRgn from GrayRgn }
 DiffRgn(grayRgn, menuBarRgn, grayRgn);
 { Now tell the Window Manager that the
   menu bar is no longer part of the
   desktop.  We do this by calling
   CalcVisBehind again.  We do not need
   to call PaintBehind first because we
   are not expanding the desktop. }
 CalcVisBehind(WindowPeek(GetWindowList), menuBarRgn);
 DisposeRgn(menuBarRgn);
 { Now redraw the menu bar on the desktop. }
 DrawMenuBar
 END { IF }
 END; { ShowMenuBar }

{$S ShowHideMBar}
FUNCTION  MenuBarVisible: BOOLEAN;
 BEGIN
 MenuBarVisible := GetMBarHeight <> 0
 END; { MenuBarVisible }

{$S ShowHideMBar}
FUNCTION  PtInMenuBar(pt: Point): BOOLEAN;
 VAR
 height:INTEGER;
 r:Rect;
 BEGIN
 height := GetMBarHeight;
 IF height = 0 THEN
 { Menu bar is hidden. }
 height := gSavedMBarHeight;
 r := screenBits.bounds;
 r.bottom := r.top + height;
 PtInMenuBar := PtInRect(pt, r)
 END; { PtInMenuBar }

{$S ShowHideMBar}
FUNCTION  HiddenMenuSelect
 (startPt: Point): LONGINT;
 VAR
 wasHidden: BOOLEAN;
 BEGIN
 wasHidden := GetMBarHeight = 0;
 IF wasHidden THEN
 { Change it temporarily. }
 SetMBarHeight(gSavedMBarHeight);
 { Now do normal MenuSelect }
 HiddenMenuSelect := MenuSelect(startPt);
 IF wasHidden THEN
 BEGIN
 { We must unhilite the menu ourselves
   before setting MBarHeight back to 0. }
 HiliteMenu(0);
 { Now change it back. }
 SetMBarHeight(0)
 END { IF }
 END; { HiddenMenuSelect }

END. { ShowHideMBar }
Listing:  HideMenuBarExample.p

{
HideMenuBarExample.p
MPW 3.0 Pascal source for menu bar hiding example.
Copyright © 1989 D. Grant Leeper.
All rights reserved.
Publication rights granted to MacTutor.
}

PROGRAM HideMenuBarExample;

USES
 Types, Resources, QuickDraw, Fonts, Events,
 Controls, Windows, Menus, TextEdit, Dialogs,
 ToolUtils, OSUtils, SegLoad, Files, Packages,
 Desk, DiskInit, Memory, OSEvents,
 Traps, ShowHideMBar;

CONST
 kSysEnvironsVersion =  1;
 
 kMinHeap = 7 * 1024;
 kMinSpace =2 * 1024;
 
 kMinDocH = 424;
 kMinDocV = 70;
 
 kScrollBarAdjust =15;
 
 kExtremeNeg =   -32768;
 kExtremePos =   32767 - 1;

 rWindow =128;
 rMenuBar = 128;
 rAboutAlert =   128;
 rFatalAlert =   129;
 
 rMessages =128;
 iSelectApp =    1;
 iSelectWind =   2;
 iAltSelectWind =3;
 iCommandSpace = 4;
 iAltCommandSpace =5;
 iClick = 6;
 iCommandClick = 7;
 
 mApple = 128;
 iAbout = 1;
 
 mFile =129;
 iClose = 1;
 iQuit =2;
 
 mEdit =130;
 iUndo =1;
 iCut = 3;
 iCopy =4;
 iPaste = 5;
 iClear = 6;
 
VAR
 gMac:  SysEnvRec;
 gHasWaitNextEvent:BOOLEAN;
 gInBackground:  BOOLEAN;
 { This keeps track of when we need to
   adjust the menus }
 gDirtyMenus:    BOOLEAN;
 { gHasMenuBar saves the visibility of the
   menu bar while we’re in the background. }
 gHasMenuBar:    BOOLEAN;
 { Create these once rather than each time
   through the event loop. }
 gOutsideRgn:    RgnHandle;
 gInsideRgn:RgnHandle;

{$S Main}
FUNCTION  IsDAWindow(window: WindowPtr): BOOLEAN;
 BEGIN
 IsDAWindow :=
 (window <> NIL) &
 (WindowPeek(window)^.windowKind < 0)
 END; { IsDAWindow }

{$S Main}
FUNCTION  IsAppWindow(window: WindowPtr): BOOLEAN;
 BEGIN
 IsAppWindow :=
 (window <> NIL) &
 (WindowPeek(window)^.windowKind =
  userKind)
 END; { IsAppWindow }

{$S Main}
PROCEDURE DoToAllAppWindows(
 PROCEDURE DoThis(window: WindowPtr));
 VAR
 window:WindowPeek;
 BEGIN
 window := WindowPeek(FrontWindow);
 WHILE window <> NIL DO
 BEGIN
 IF window^.windowKind = userKind THEN
 DoThis(WindowPtr(window));
 window := window^.nextWindow
 END { WHILE }
 END; { DoToAllAppWindows }

{$S Main}
PROCEDURE FatalError;
 VAR
 itemHit: INTEGER;
 BEGIN
 SetCursor(arrow);
 itemHit := CautionAlert(rFatalAlert, NIL);
 { Be sure the menu bar is visible at exit
   time, but check first for the 128K ROM
   since we may have been called because
   it’s not available. }
 IF gMac.machineType >= 0 THEN
 ShowMenuBar;
 ExitToShell
 END; { FatalError }

{$S Main}
FUNCTION  DoCloseWindow(window: WindowPtr): BOOLEAN;
 BEGIN
 DoCloseWindow := TRUE;
 IF IsAppWindow(window) THEN
 BEGIN
 CloseWindow(window);
 DisposPtr(Ptr(window))
 END { IF }
 ELSE IF IsDAWindow(window) THEN
 CloseDeskAcc(WindowPeek(window)^.windowKind)
 END; { DoCloseWindow }

{$S Initialize}
PROCEDURE BringAppToFront;
 VAR
 count: INTEGER;
 event: EventRecord;
 BEGIN
 FOR count := 1 TO 3 DO
 IF EventAvail(everyEvent, event) THEN
 ; { Ignore it }
 END; { BringAppToFront }

{$S Initialize}
PROCEDURE Initialize;
 VAR
 bIgnore: BOOLEAN;
 event: EventRecord;
 ignore:OSErr;
 total: LONGINT;
 contig:LONGINT;
 storage: Ptr;
 window:WindowPtr;
 menuBar: Handle;
 
 BEGIN
 InitGraf(@thePort);
 InitFonts;
 InitWindows;
 InitMenus;
 TEInit;
 InitDialogs(NIL);
 InitCursor;
 
 BringAppToFront;
 
 { SysEnvirons must be called before calling
   FatalError. }
 ignore := SysEnvirons(kSysEnvironsVersion, gMac);
 
 { Need 128K ROMS to change menu bar height. }
 IF gMac.machineType < 0 THEN
 FatalError;
 
 { The menu bar can be hidden now if desired. }
 HideMenuBar;
 
 IF ORD(GetApplLimit) - ORD(ApplicZone) <
    kMinHeap THEN
 FatalError;
 
 PurgeSpace(total, contig);
 IF total < kMinSpace THEN
 FatalError;
 
 gHasWaitNextEvent :=
 GetTrapAddress(_Unimplemented) <>
 NGetTrapAddress(_WaitNextEvent, ToolTrap);
 
 gInBackground := FALSE;
 
 storage := NewPtr(SizeOf(WindowRecord));
 IF storage = NIL THEN
 FatalError;
 IF gMac.hasColorQD THEN
 window := GetNewCWindow(rWindow, storage, Pointer(-1))
 ELSE
 window := GetNewWindow(rWindow, storage, Pointer(-1));
 IF window = NIL THEN
 FatalError;
 
 menuBar := GetNewMBar(rMenuBar);
 IF menuBar = NIL THEN
 FatalError;
 SetMenuBar(menuBar);
 DisposHandle(menuBar);
 AddResMenu(GetMHandle(mApple), ‘DRVR’);
 DrawMenuBar;
 gDirtyMenus := TRUE;
 
 gOutsideRgn := NewRgn;
 gInsideRgn := NewRgn
 END; { Initialize }

{$S Main}
PROCEDURE Terminate;
 VAR
 window:WindowPtr;
 BEGIN
 window := FrontWindow;
 WHILE window <> NIL DO
 IF DoCloseWindow(window) THEN
 window := FrontWindow
 ELSE
 Exit(Terminate);
 { Must restore menu bar
   before quitting }
 ShowMenuBar;
 ExitToShell
 END; { Terminate }

{$S Main}
PROCEDURE AdjustMenus;
 VAR
 window:WindowPtr;
 appWind: BOOLEAN;
 daWind:BOOLEAN;
 redraw:BOOLEAN;
 menu:  MenuHandle;
 wasEnabled:BOOLEAN;
 BEGIN
 window := FrontWindow;
 appWind := IsAppWindow(window);
 daWind := IsDAWindow(window);
 redraw := FALSE;
 
 menu := GetMHandle(mFile);
 IF daWind THEN
 EnableItem(menu, iClose)
 ELSE
 DisableItem(menu, iClose);
 
 menu := GetMHandle(mEdit);
 wasEnabled := Odd(menu^^.enableFlags);
 IF daWind THEN
 BEGIN
 EnableItem(menu, 0);
 EnableItem(menu, iUndo);
 EnableItem(menu, iCut);
 EnableItem(menu, iCopy);
 EnableItem(menu, iPaste);
 EnableItem(menu, iClear)
 END { IF }
 ELSE
 BEGIN
 DisableItem(menu, 0);
 DisableItem(menu, iUndo);
 DisableItem(menu, iCut);
 DisableItem(menu, iCopy);
 DisableItem(menu, iClear);
 DisableItem(menu, iPaste)
 END; { ELSE }
 IF Odd(menu^^.enableFlags) <> wasEnabled THEN
 redraw := TRUE;
 
 IF redraw THEN
 DrawMenuBar
 END; { AdjustMenus }

{$S Main}
PROCEDURE DoMenuCommand(menuResult: LONGINT);
 VAR
 menu:  INTEGER;
 item:  INTEGER;
 ignore:INTEGER;
 name:  Str255;
 window:WindowPtr;
 bIgnore: BOOLEAN;
 
 BEGIN
 menu := HiWrd(menuResult);
 item := LoWrd(menuResult);
 CASE menu OF
 mApple:
 CASE item OF
 iAbout:
 ignore := Alert(rAboutAlert, NIL);
 
 OTHERWISE
 BEGIN
 GetItem(GetMHandle(mApple),
 item, name);
 ignore := OpenDeskAcc(name);
 gDirtyMenus := TRUE
 END { OTHERWISE }
 END; { CASE }
 
 mFile:
 CASE item OF
 iClose:
 BEGIN
 window := FrontWindow;
 IF IsDAWindow(window) THEN
 CloseDeskAcc(WindowPeek(window)^.windowKind);
 gDirtyMenus := TRUE
 END; { iClose }
 iQuit:
 Terminate
 END; { CASE }
 mEdit:
 bIgnore := SystemEdit(item - 1)
 END; { CASE }
 HiliteMenu(0)
 END; { DoMenuCommand }

{$S Main}
PROCEDURE DrawWindow(window: WindowPtr);
 VAR
 str: Str255;
 BEGIN
 SetPort(window);
 EraseRect(window^.portRect);
 DrawGrowIcon(window);
 
 { We display different messages here
   depending on our foreground/background
   and activate/inactivate states. }
 
 IF gInBackground THEN
 BEGIN
 GetIndString(str, rMessages, iSelectApp);
 MoveTo(10, 32);
 DrawString(str)
 END { IF }
 
 ELSE IF window <> FrontWindow THEN
 BEGIN
 IF MenuBarVisible THEN
 GetIndString(str, rMessages, iSelectWind)
 ELSE
 GetIndString(str, rMessages, iAltSelectWind);
 MoveTo(10, 32);
 DrawString(str)
 END { ELSE IF }
 
 ELSE
 IF MenuBarVisible THEN
 BEGIN
 MoveTo(10, 32);
 GetIndString(str, rMessages, iCommandSpace);
 DrawString(str)
 END { IF }
 ELSE
 BEGIN
 MoveTo(10, 16);
 GetIndString(str, rMessages, iAltCommandSpace);
 DrawString(str);
 MoveTo(10, 32);
 GetIndString(str, rMessages, iClick);
 DrawString(str);
 MoveTo(10, 48);
 GetIndString(str, rMessages, iCommandClick);
 DrawString(str)
 END { ELSE }
 END; { DrawWindow }

{$S Main}
PROCEDURE InvalContentRgn(window: WindowPtr);
 VAR
 r:Rect;
 BEGIN
 SetPort(window);
 r := window^.portRect;
 r.bottom := r.bottom - kScrollBarAdjust;
 r.right := r.right - kScrollBarAdjust;
 InvalRect(r)
 END; { InvalContentRgn }

{$S Main}
PROCEDURE InvalAppWindContents;
{ Since our window may be behind some DA windows
  we must check all the windows in our layer. }
 BEGIN
 DoToAllAppWindows(InvalContentRgn)
 END; { InvalAppWindContents }

{$S Main}
PROCEDURE InvalGrowRgn(window: WindowPtr);
 VAR
 r:Rect;
 BEGIN
 SetPort(window);
 r := window^.portRect;
 r.top := r.bottom - kScrollBarAdjust;
 InvalRect(r);
 r := window^.portRect;
 r.left := r.right - kScrollBarAdjust;
 InvalRect(r)
 END; { InvalGrowRgn }

{$S Main}
PROCEDURE DoGrowWindow(window: WindowPtr;
    event: EventRecord);
 VAR
 tempRect:Rect;
 growResult:LONGINT;
 BEGIN
 WITH screenBits.bounds DO
 SetRect(tempRect, kMinDocH, kMinDocV, right, bottom);
 growResult := GrowWindow(window, event.where, tempRect);
 IF growResult <> 0 THEN
 BEGIN
 InvalGrowRgn(window);
 SizeWindow(window, LoWrd(growResult),
    HiWrd(growResult), TRUE);
 InvalGrowRgn(window)
 END { IF }
 END; { DoGrowWindow }

{$S Main}
PROCEDURE DoZoomWindow(window: WindowPtr; part: INTEGER);
 BEGIN
 SetPort(window);
 EraseRect(window^.portRect);
 ZoomWindow(window, part, FALSE)
 END; { DoZoomWindow }

{$S Main}
PROCEDURE DoUpdate(window: WindowPtr);
 BEGIN
 IF IsAppWindow(window) THEN
 BEGIN
 BeginUpdate(window);
 IF NOT EmptyRgn(window^.visRgn) THEN
 DrawWindow(window);
 EndUpdate(window)
 END { IF }
 END; { DoUpdate }

{$S Main}
PROCEDURE DoActivate(window: WindowPtr;
  becomingActive: BOOLEAN);
 BEGIN
 IF IsAppWindow(window) THEN
 BEGIN
 { Message to user changes when
   activated or deactivated. }
 InvalContentRgn(window);
 DrawGrowIcon(window);
 gDirtyMenus := TRUE
 END { IF }
 END; { DoActivate }

{$S Main}
PROCEDURE DoDisk(message: LONGINT);
 CONST
 kDILeft =70;
 kDITop = 50;
 VAR
 where: Point;
 BEGIN
 IF HiWrd(message) <> noErr THEN
 BEGIN
 SetPt(where, kDILeft, kDITop);
 IF DIBadMount(where, message) = 0 THEN
 { Ignore it }
 END { IF }
 END; { DoDisk }

{$S Main}
PROCEDURE DoSuspendResume(suspend: BOOLEAN);
 BEGIN
 gInBackground := suspend;
 
 IF suspend THEN
 { Save menu bars visibility for when we resume
   then force the menu bar to be displayed. }
 BEGIN
 gHasMenuBar := MenuBarVisible;
 ShowMenuBar
 END { IF }
 
 ELSE IF NOT gHasMenuBar THEN
 { Resuming, hide the menu bar if it was
   hidden prior to our suspension. }
 HideMenuBar;
 
 DoActivate(FrontWindow, NOT suspend);
 
 { Change message to user when
   suspended or resumed. }
 InvalAppWindContents
 END; { DoSuspendResume }

{$S Main}
PROCEDURE AdjustCursor(mouse: Point;
    cursorRgn: RgnHandle);
 VAR
 window:WindowPtr;
 insideRect:Rect;
 BEGIN
 window := FrontWindow;
 IF NOT gInBackground &
    NOT IsDAWindow(window) THEN
 BEGIN
 SetRectRgn(gOutsideRgn,
 kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
 
 IF IsAppWindow(window) THEN
 BEGIN
 insideRect := window^.portRect;
 insideRect.bottom :=
 insideRect.bottom - kScrollBarAdjust;
 insideRect.right :=
 insideRect.right - kScrollBarAdjust;
 SetPort(window);
 LocalToGlobal(insideRect.topLeft);
 LocalToGlobal(insideRect.botRight);
 RectRgn(gInsideRgn, insideRect)
 END; { IF }
 
 DiffRgn(gOutsideRgn, gInsideRgn, gOutsideRgn);
 
 IF PtInRgn(mouse, gInsideRgn) THEN
 BEGIN
 SetCursor(GetCursor(plusCursor)^^);
 CopyRgn(gInsideRgn, cursorRgn)
 END { IF }
 ELSE
 BEGIN
 SetCursor(arrow);
 CopyRgn(gOutsideRgn, cursorRgn)
 END; { ELSE }
 
 SetEmptyRgn(gOutsideRgn);
 SetEmptyRgn(gInsideRgn)
 END { IF }
 END; { AdjustCursor }

{$S Main}
PROCEDURE DoEvent(event: EventRecord);
 CONST
 kOSEvent = app4Evt;
 kSuspendResumeMessage =  1;
 kResumeMask =   1;
 VAR
 part:  INTEGER;
 window:WindowPtr;
 key: CHAR;
 BEGIN
 CASE event.what OF
 mouseDown:
 BEGIN
 part := FindWindow(event.where, window);
 
 CASE part OF
 inDesk:
 IF PtInMenuBar(event.where) THEN
 { User clicked in hidden menu bar.  Lets show
   off some tricks. }
 BEGIN
 { Show menu bar first if
   command key pressed,
   else just show menus
   without the bar. }
 IF BAnd(event.modifiers, cmdKey) <> 0 THEN
 ShowMenuBar;
 DoMenuCommand(HiddenMenuSelect(event.where));
 { If we showed the menu bar here we must be
   sure HiliteMenu(0) is called before we hide
   it again. In our case DoMenuCommand calls it
   for us. }
 IF BAnd(event.modifiers, cmdKey) <> 0 THEN
 HideMenuBar
 END; { IF }
 inMenuBar:
 DoMenuCommand(MenuSelect(event.where));
 inSysWindow:
 SystemClick(event, window);
 
 inContent:
 IF window <> FrontWindow THEN
 SelectWindow(window);
 inDrag:
 DragWindow(window, event.where, screenBits.bounds);
 inGrow:
 DoGrowWindow(window, event);
 inZoomIn, inZoomOut:
 IF TrackBox(window,event.where, part) THEN
 DoZoomWindow(window, part)
 END { CASE }
 END; { mouseDown }
 keyDown, autoKey:
 BEGIN
 key := Chr(BAnd(event.message, charCodeMask));
 IF BAnd(event.modifiers, cmdKey) <> 0 THEN
 IF event.what = keyDown THEN
 IF key = ‘ ‘ THEN
 { User typed command-space so
   toggle the menu bar. }
 BEGIN
 IF MenuBarVisible THEN
 HideMenuBar
 ELSE
 ShowMenuBar;
 { Change message to user when menu is hidden
   or made visible. }
 InvalAppWindContents
 END { IF }
 ELSE
 DoMenuCommand(
 MenuKey(key))
 END; { keyDown, autoKey }
 activateEvt:
 DoActivate(WindowPtr(event.message),
    BAnd(event.modifiers, activeFlag) <> 0);
 updateEvt:
 DoUpdate(WindowPtr(event.message));
 diskEvt:
 DoDisk(event.message);
 kOSEvent:
 CASE BAnd(BRotL(event.message, 8), $FF) OF
 kSuspendResumeMessage:
 DoSuspendResume(BAnd(event.message,
 kResumeMask) = 0)
 END { CASE }
 END { CASE }
 END; { DoEvent }

{$S Main}
FUNCTION  GlobalMouse: Point;
 CONST
 kNoEvents =0;
 VAR
 ignore:BOOLEAN;
 event: EventRecord;
 BEGIN
 ignore := OSEventAvail(kNoEvents, event);
 GlobalMouse := event.where
 END; { GlobalMouse }

{$S Main}
PROCEDURE EventLoop;
 VAR
 cursorRgn: RgnHandle;
 gotEvent:BOOLEAN;
 event: EventRecord;
 BEGIN
 cursorRgn := NewRgn;
 WHILE TRUE DO
 BEGIN
 IF gDirtyMenus THEN
 BEGIN
 AdjustMenus;
 gDirtyMenus := FALSE
 END; { IF }
 
 AdjustCursor(GlobalMouse, cursorRgn);
 
 IF gHasWaitNextEvent THEN
 gotEvent :=
 WaitNextEvent(everyEvent, event, 30, cursorRgn)
 ELSE
 BEGIN
 SystemTask;
 gotEvent := GetNextEvent(everyEvent,
  event)
 END; { ELSE }
 
 IF gotEvent THEN
 AdjustCursor(event.where, cursorRgn);
 
 DoEvent(event)
 END { WHILE }
 END; { EventLoop }

PROCEDURE _DataInit; EXTERNAL;

BEGIN
UnloadSeg(@_DataInit);
MaxApplZone;
Initialize;
UnloadSeg(@Initialize);
EventLoop
END. { HideMenuBarExample }
Listing:  HideMenuBarExample.r
/*
HideMenuBarExample.r
MPW 3.0 Rez source for menu bar hiding example.
Copyright © 1989 D. Grant Leeper.
All rights reserved.
Publication rights granted to MacTutor.
*/

#include “Types.r”
#include “SysTypes.r”

#define kMinSize 24
#define kPrefSize32

#define rWindow  128
#define rMenuBar 128
#define rAboutAlert128
#define rFatalAlert129
#define rMessages128

#define mApple   128
#define mFile    129
#define mEdit    130

resource ‘WIND’ (rWindow, preload, purgeable) {
 {30, 80, 100, 504},
 zoomDocProc, visible, noGoAway, 0x0,
 “Menu Bar Hiding Example”
};

resource ‘MBAR’ (rMenuBar, preload) {
 { mApple, mFile, mEdit };
};

resource ‘MENU’ (mApple, preload) {
 mApple, textMenuProc,
 0x7FFFFFFF & ~0b10,
 enabled, apple,
 {
 “About HideMenuBarExample ”,
 noicon, nokey, nomark, plain;
 “-”,
 noicon, nokey, nomark, plain
 }
};

resource ‘MENU’ (mFile, preload) {
 mFile, textMenuProc,
 0b10,
 enabled, “File”,
 {
 “Close”,
 noicon, “W”, nomark, plain;
 “Quit”,
 noicon, “Q”, nomark, plain
 }
};

resource ‘MENU’ (mEdit, preload) {
 mEdit, textMenuProc,
 0,
 enabled, “Edit”,
  {
 “Undo”,
 noicon, “Z”, nomark, plain;
 “-”,
 noicon, nokey, nomark, plain;
 “Cut”,
 noicon, “X”, nomark, plain;
 “Copy”,
 noicon, “C”, nomark, plain;
 “Paste”,
 noicon, “V”, nomark, plain;
 “Clear”,
 noicon, nokey, nomark, plain
 }
};

resource ‘ALRT’ (rAboutAlert, purgeable) {
 {60, 40, 184, 340},
 rAboutAlert,
 { /* array: 4 elements */
 /* [1] */
 OK, visible, silent,
 /* [2] */
 OK, visible, silent,
 /* [3] */
 OK, visible, silent,
 /* [4] */
 OK, visible, silent
 }
};

resource ‘DITL’ (rAboutAlert, purgeable) {
 { /* array DITLarray: 5 elements */
 /* [1] */
 {92, 110, 112, 190},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {4, 78, 20, 222},
 StaticText {
 disabled,
 “HideMenuBarExample”
 },
 /* [3] */
 {24, 37, 40, 262},
 StaticText {
 disabled,
 “Copyright © 1989 D. Grant Leeper.”
 },
 /* [4] */
 {44, 86, 60, 214},
 StaticText {
 disabled,
 “All rights reserved.”
 },
 /* [5] */
 {64, 19, 80, 281},
 StaticText {
 disabled,
 “Publication rights granted”
 “ to MacTutor.”
 }
 }
};

resource ‘ALRT’ (rFatalAlert, purgeable) {
 {40, 20, 144, 312},
 rFatalAlert,
 { /* array: 4 elements */
 /* [1] */
 OK, visible, silent,
 /* [2] */
 OK, visible, silent,
 /* [3] */
 OK, visible, silent,
 /* [4] */
 OK, visible, silent
 }
};

resource ‘DITL’ (rFatalAlert, purgeable) {
 { /* array DITLarray: 2 elements */
 /* [1] */
 {72, 180, 92, 260},
 Button {
 enabled,
 “OK”
 },
 /* [2] */
 {10, 60, 58, 276},
 StaticText {
 disabled,
 “HideMenuBarExample - An “
 “unexpected error has occurred. “
 “(Probably out of memory.)”
 }
 }
};

resource ‘STR#’ (rMessages, purgeable) {
 { /* array stringArray: 7 elements */
 /* [1] */
 “Bring application to front to hide “
 “menu bar.”,
 /* [2] */
 “Bring window to front to hide menu bar.”,
 /* [3] */
 “Bring window to front to show menu bar.”,
 /* [4] */
 “Press Command-Space to hide menu bar.”,
 /* [5] */
 “Press Command-Space to show menu bar, “
 “or try clicking on the “,
 /* [6] */
 “desktop where a menu title should be, “
 “or try command-clicking “,
 /* [7] */
 “on the desktop where the menu bar “
 “should be.”
 }
};

/*
We are MultiFinder aware and friendly.
We are probably 32 bit compatible as well but
have not been tested in a 32 bit environment.
*/

resource ‘SIZE’ (-1) {
 dontSaveScreen,
 acceptSuspendResumeEvents,
 enableOptionSwitch,
 canBackground,
 multiFinderAware,
 backgroundAndForeground,
 dontGetFrontClicks,
 ignoreChildDiedEvents,
 not32BitCompatible, /* Not tested */
 reserved,
 reserved,
 reserved,
 reserved,
 reserved,
 reserved,
 reserved,
 kPrefSize * 1024,
 kMinSize * 1024 
};

resource ‘vers’ (1) {
 0x1,
 0x0,
 release,
 0x0,
 verUs,
 “1.0”,
 “1.0 © 1989 D. Grant Leeper\n”
 “All rights reserved.”
};

resource ‘vers’ (2) {
 0x1,
 0x0,
 release,
 0x0,
 verUs,
 “1.0”,
 “Hiding The Menu Bar”
};

 
AAPL
$116.47
Apple Inc.
+0.16
MSFT
$47.98
Microsoft Corpora
-0.72
GOOG
$537.50
Google Inc.
+2.67

MacTech Search:
Community Search:

Software Updates via MacUpdate

StatsBar 1.9 - Monitor system processes...
StatsBar gives you a comprehensive and detailed analysis of the following areas of your Mac: CPU usage Memory usage Disk usage Network and bandwidth usage Battery power and health (MacBooks only)... Read more
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

Latest Forum Discussions

See All

Ubisoft Gives Everyone Two New Ways to E...
Ubisoft Gives Everyone Two New Ways to Earn In-Game Stuff for Far Cry 4 Posted by Jessica Fisher on November 21st, 2014 [ permalink ] | Read more »
Golfinity – Tips, Tricks, Strategies, an...
Dig this: Would you like to know what we thought of being an infinite golfer? Check out our Golfinity review! Golfinity offers unlimited ways to test your skills at golf. Here are a few ways to make sure your score doesn’t get too high and your... | Read more »
Dark Hearts, The Sequel to Haunting Meli...
Dark Hearts, The Sequel to Haunting Melissa, is Available Now Posted by Jessica Fisher on November 21st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Meowza! Toyze Brings Talking Tom to Life...
Meowza! | Read more »
Square Enix Announces New Tactical RPG f...
Square Enix Announces New Tactical RPG for Mobile, Heavenstrike Rivals. Posted by Jessica Fisher on November 21st, 2014 [ permalink ] With their epic stories and gorgeous graphics, | Read more »
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 »

Price Scanner via MacPrices.net

Save up to $400 with Apple refurbished 2014 1...
The Apple Store has restocked Apple Certified Refurbished 2014 15″ Retina MacBook Pros for up to $400 off the cost of new models. An Apple one-year warranty is included with each model, and shipping... Read more
New 13-inch 1.4GHz MacBook Air on sale for $8...
 Adorama has the 2014 13″ 1.4GHz/128GB MacBook Air on sale for $899.99 including free shipping plus NY & NJ tax only. Their price is $100 off MSRP. B&H Photo has the 13″ 1.4GHz/128GB MacBook... Read more
Apple Expected to Reverse Nine-Month Tablet S...
Apple and Samsung combined accounted for 62 percent of the nearly 36 million branded tablets shipped in 3Q 2014, according to early vendor shipment share estimates from market intelligence firm ABI... Read more
Stratos: 30 Percent of US Smartphone Owners t...
Stratos, Inc., creator of the Bluetooth Connected Card Platform, has announced results from its 2014 Holiday Mobile Payments Survey. The consumer survey found that nearly one out of three (30 percent... Read more
2014 1.4GHz Mac mini on sale for $449, save $...
 B&H Photo has lowered their price on the new 1.4GHz Mac mini to $449.99 including free shipping plus NY tax only. Their price is $50 off MSRP, and it’s the lowest price available for this new... Read more
Check Apple prices on any device with the iTr...
MacPrices is proud to offer readers a free iOS app (iPhones, iPads, & iPod touch) and Android app (Google Play and Amazon App Store) called iTracx, which allows you to glance at today’s lowest... Read more
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
Notebook PC Shipments Rise Year-Over-Year as...
According to preliminary results from the upcoming DisplaySearch Quarterly Mobile PC Shipment and Forecast Report, the global notebook PC market grew 10 percent year-over-year in Q3’14 to 49.4... 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.