TweetFollow Us on Twitter

Windows Holes
Volume Number:3
Issue Number:10
Column Tag:Pascal Procedures

Blasting Holes in Windows

By Greg Marriott, MacHax™ Group, Bryan, Texas

How To Build A Laser Cannon: A Home S.D.I. Project

Bit O’ History

I wish I came up with the idea to blast holes in windows, but I didn’t. The credit goes to Andrew Donoho and Darin Adler. Andrew is the author of MacSpin, a 3-d data analysis tool. MacSpin allows a user to rotate a “cloud” of data points around any of three axes in real time. Because of its highly interactive nature, Andrew likes to refer to it as a thinking man’s video game. He and Darin got together and decided that MacSpin was missing a feature essential to successful video games: laser cannons. They envisioned a user holding down command-shift-option-capsLock and being rewarded by laser turrents appearing in the corners of the data window. Add in some crosshairs with range and elevation readouts, and the user could blast away! They figured laser cannons would be especially useful in MacSpin, where unwanted data points could be annihilated, thus saving a pet theory from bothersome reality.

Andrew continued to joke about actually implementing laser cannons. That’s how my partner, Scott Boyd, heard about it. Scott was working closely with Andrew on enhancements for MacSpin when the subject of laser cannons came up. Scott knows a good idea when he hears one (most of the time), so he immediately urged Andrew to stop joking and do it. More pressing concerns kept them both busy for a while, but the idea wouldn’t die.

Laser Cannons Are Born

I learned about laser cannons in a phone conversation with Scott. I know a good idea when I hear one, too (I hope...). They were busy. I wasn’t. By the time Scott came home from Austin a couple of days later, I had the first incarnation of Blast finished. It was an application that brought up a window, and made holes wherever the cursor was when the mouse button was pressed. The holes were plain and round, and it ran silently. The holes weren’t even centered under the cursor. But gridlines drawn in the window showed that the holes were “not there.” That is, holes had been cut out of the structure of the window. Wow laser cannons.

Fig. 1 Blasting holes in Full Paint's windows! (note how the cursor changes over a hole to the arrow, proof that it is not in the window!)

“Useless Interface” Concerns

Scott and I talked about what the holes should look like. After some discussion, he drew some sample holes in MacDraw. After a while, he had something we both liked. I took the coordinates of the vertices around the hole, and put in some code to make a region (instead of just using circles). While I was at it, I started centering the hole under the cursor. So far, so good.

Sound came next. Poking holes in things isn’t very much fun if you don’t get some sort of aural feedback. We discussed all sorts of options, from simple beeps to elaborate crashing noises. I chose the easy route and used the Sound Driver to make some square-wave sound.

Making sound on the Mac is pretty easy if you’re willing to settle for single voice tones. Each tone is described by a trio of values known as a “triplet.” These numbers describe the pitch, volume, and duration of the tones you want to play. I decided to use twenty triplets. The last triplet has zero for all three values, to tell the Sound Driver to stop making noise. For the other nineteen, I chose a starting value, then decreased the pitch and volume of each succeeding tone. This gives the impression of something moving into the distance, like a train’s whistle as it heads away from you.

Now We’re Getting Somewhere

Blast didn’t change much after I added sound. The biggest change was in “packaging.” I wanted Blast to be available from anywhere, so I decided to make it into an FKEY. But as an FKEY, Blast had to stop counting on having access to global variables and resources. QuickDraw globals such as screenBits and thePort may not be available while an FKEY is running. And, counting on certain resources being installed along with the FKEY is a sure way to see everybody’s favorite bomb box. So, Blast became a procedure in a UNIT. The procedure has everything in it Blast needs to do its dirty work. [The version presented here is compatible with both MPW Pascal and LS Pascal. The unit can be either installed as an FKEY or you can call the unit from a program. In the code listing, a USES statement is presented for both MPW and LS Pascal. Since LS Pascal requires code resources to have a MAIN entry point, a procedure with the name MAIN was added to the unit, which calls BlastIt. This MAIN can be removed for MPW. -Ed]

Gory Details

The first thing I do in Blast is allocate a non-relocatable block for the sound buffer, and fill it with triplets. Then I go about putting up the crosshair cursor. I want to be polite and give the user their original cursor back when Blast is done, so I have to know what it is. But there isn’t a call to get the current cursor. Apple seems to feel that the cursor should be “write-only.” I have to dip into low memory and suck the cursor out the hard way. I suppose this is “against the rules,” but I refuse to sit back and hope the application running is smart enough to update its cursor when Blast is through. I set up the crosshair cursor and do a SetCursor call. Remember what I said about no resources? The crosshair cursor is hard-coded into Blast and the way I set it up is by using StuffHex to load up a cursor variable. It looks kind of gnarly, but it helps make Blast self-contained.

Once the cursor is up (so the user gets some immediate feedback), I pre-fabricate the hole. To do this I open a region, and draw the outline of the hole. OpenRegion hides the QuickDraw pen, so the user doesn’t get to see any drawing happen. Then I close the region and move it to the origin, ( 0, 0 ). This makes the size calculations simple, since the top and left coordinates are both zero. I want to know how big the hole is in order to “add in” a round part (sort of like a bullet hole). I make another region shaped like a circle, and use UnionRgn to add it to the jagged part. After the composite hole is prepared, Blast is almost ready to go. First, though, I set the current port to be the window manager port (the whole screen). This is so the coordinates of the holes line up with the windows’ regions out on the desktop.

The Heart Of The Matter

The main loop is pretty straightforward. Wait for a mouse click. If the click is in the content region of any window, go to work. Initiate some asynchrounous sound by calling StartSound. Move the hole to center it under the mouse. Subtract the hole (via DiffRgn) from the content region and structure region of the window. Presto! Laser cannons. After blasting a window, all the windows underneath the blasted one need to be notified that they have newly visible areas. I use the low-level Window Manager call CalcVisBehind to do this. It recalculates the visible regions of all windows under the given window that intersect a certain region (the hole region). PaintBehind is called to paint newly visible areas, including the desktop. The new system paints windows with their background patterns, instead of always painting white like the old system.

If the user clicks anywhere but a content region, Blast exits. It throws away the hole region and the sound buffer, then restores the cursor and the old port. However, the windows retain their missing holes so you can drag a window around and see the windows behind through the holes. You can even scroll the window and watch the contents move around the hole! Only when you cause the window manager to reconstruct the window such as growing or zooming the window, do the holes go away. See figure 1.

FKEY, What’s An FKEY?

Now for a few words about FKEYs. The Mac deals with FKEYs behind the scenes by intercepting key-down events when GetNextEvent is called. If an FKEY resource with the ID number of the key that was hit is found, the system loads it in and executes it. When the FKEY is done, it passes control back to the system, which then flushes the event and pretends it never happened.

Blast can be called up from within any program that calls GetNextEvent. As a matter of fact, Blast can be called recursively from within itself, since it calls GetNextEvent. This presents no real problem, since Blast carries its own local variables around. I guess the only limit is how much stack space you have, since each activation uses up several bytes of the stack.

The Recipe for MPW

Making “non-applications” is relatively simple in MPW, as long as you pay attention to a few technical details. I made Blast part of a Pascal UNIT so the compiler wouldn’t try to create a main entry point. If it was a PROGRAM, the compiler would stick in a whole bunch of global variable initialization code and try to identify an entry point. FKEYs don’t have global variables (traditionally accessed relative to register A5), so any extra code provided by the compiler is decidedly unwelcome! [Note that for LS Pascal, a main entry point is required! But the DA PasLib file is used instead of the regular PasLib so that none of the initialization for a program is done. By clicking on the code resource option, everything gets built correctly for you. See figures 2,3 and 4. -Ed]

Once the compiler is through chewing on it, the resulting object file (the .p.o file) is passed through the linker. The linker puts in any glue code needed by functions called by Blast. Glue code is most commonly used to interface between Pascal, with its stack-based calling convention, and some parts of the Mac ROM that are register-based. The glue takes parameters off the stack and puts them in registers before calling the ROM routines. Then it takes any result from a register and puts it on the stack before returning to the main program. Another kind of glue is used for range checking by the compiler. The compiler calls glue routines to check the length of strings and such when range checking is turned on.

After the glue is taken care of, the linker expects to be told where the entry point is. The -m option on the linker let me point to the proper procedure in the Blast UNIT. The linker makes sure that the very first instruction in the resulting program jumps to the entry point. An FKEY resource is just like a CODE resource without any jump table information. With the -rt option I told the linker to create FKEY resources instead of CODE resources (the default). I also told the linker to rename the main code segment from Main to BlastKey with the -sn option. This provides a reminder when viewing the resource in ResEdit. I use ResEdit to install the FKEY in the system file. FKEY Installer and FKEY Manager should work just as well.

Adding Blast to Hypercard

Everyone I’ve talked to about WildCard (now known as HyperCard, but I think that name is really dumb) is impressed by it. One of the neatest features is the ability to compile your own commands and add them to WildCard. I recently got ahold of some sketchy documentation about these XCMD resources and decided to make Blast into a WildCard command. The only difference between an FKEY and a XCMD is that XCMDs take a single argument on the stack. WildCard passes a pointer to a block full of information to the XCMD upon activation. Inside that block of information are all sorts of goodies, like handles to command-line arguments, a place for a result code, and several fields to allow the XCMD to communicate directly with WildCard. I wasn’t really interested in all that parameter stuff (yet!), so I ignored it for the moment. All I had to do to make Blast WildCard compatible was to add a formal parameter to the procedure in the UNIT. I just changed its declaration from PROCEDURE BlastIt; to PROCEDURE BlastIt( aParam : Ptr );. Then I changed the link statement to produce XCMD resources instead of FKEY resources. Voilá, a brand new WildCard command. By the way, the name of the resource is important here, because that’s how WildCard knows which XCMD is for which command.

Up On The Soap Box

I don’t know who made up some of the “rules,” but they’re not going to be too happy with Blast. I managed to break quite a few of them along the way. The first infraction is sneaking into low memory to get the current cursor. Using any low memory globals is frowned upon. Look at all the trouble Think got into when they used BasicGlobs. For those that don’t know, BasicGlobs was to be used by MacBasic, which never made it to market. Think’s Lightspeed C generated code that used it for a scratch area. Apple started to use it in System 4.1, blowing away a whole bunch of programs. Think has corrected the problem, but they blame Apple for changing their minds about using BasicGlobs. The way I see it, anybody who uses low memory areas without express written approval from Apple deserves what they get. Apple has stated many times that low memory is off limits. In fact, the area we know as low memory is going to disappear in future architectures. But since I’m only reading (and not writing) low memory, I’ll just get trash if they ever move the cursor storage area.

The next infraction is a biggy. Blast directly modifies the fields of a windowRecord, namely the strucRgn and contRgn. Apple is really touchy about windowRecords, especially since the invention of Juggler (now known as MultiFinder, but I think that name is really dumb, too). Juggler does all sorts of neat things with windows and window lists to manage multiple applications. Blast isn’t directly affected by this, but Juggler proves that Apple is serious about changing window handling without notice. When Apple gives us windowing hardware, programs like Blast will be next to impossible (but I’m gonna try it anyway! ).

The next one is more a matter of style, but could cause problems. I just assume that Blast will have plenty of memory to make the sound buffer and the hole regions. I wouldn’t recommend using Blast when you’ve got a bunch of unsaved data and can’t afford to crash with an out of memory error.

Credits, etc...

Thanks to Andrew and Darin for having the idea, and to Scott for planting the seed in my head. Speaking of seeds, TECHNOSTUD (a.k.a. Steve Knouse) helped out by showing Blast to anyone he could drag over to a Macintosh for two minutes. Steve is sort of like a reverse Johnny Appleseed. He goes around sowing MacHax™ programs on Apples everywhere. Thanks for all your support, Steve. And thanks to Dave Smith, who put me on a panel at the Boston MacWorld Expo. That’s where Blast made its public debut. To all the attendees of that panel, here is source code, only two months late.

I can be reached at any of the following:

3420D Sandra St.

Bryan, TX 77801

(409) 846-4102

AppleLink: D0635

MCIMail: Greg Marriott

BITNet: max@tamlsr

Fig. 2 LS Pascal Project Definition

UNIT BlastStuff;

{MPW and LS Pascal Version}

INTERFACE

{ For MPW, use the following USES statement}
 USES  {$LOAD fkeyblast.dump}
      MemTypes, QuickDraw, OSIntf, ToolIntf;

{ For LS Pascal, use the following USES statement}
 USES
 ROM85;

 PROCEDURE BlastIt;
 PROCEDURE Main; {not needed for MPW}

IMPLEMENTATION

PROCEDURE BlastIt;
 CONST
 buffSize = 122; 
 { sound takes 2, 20 triplets = 120 bytes }
 VAR
 holeRgn, circleRgn : RgnHandle;
 theEvent : EventRecord;
 stopIt : Boolean;
 whichWindow : WindowPtr;
 thisWindow : WindowPeek;
 i, dur, cnt, minSize:Integer; 
 pictWidth, thePart : Integer;
 blastPict : Pichandle;
 anotherRect, circleRect, tempRect : Rect;
 mouseSpot, holeSize, middlePoint : Point;
 wPort, oldPort, tempPort : GrafPtr;
 DeskPattern : ^Pattern;
 crossHairs, oldCursor : Cursor;
 TheCurs : ^Cursor;
 squareWavePtr : SWSynthPtr;
 amp : integer;

 BEGIN

    { let’s set up sounds... }
 squareWavePtr := SWSynthPtr(NewPtr(buffSize));
 squareWavePtr^.mode := swMode; { squarewave mode }
 cnt := 400;
 amp := 150;

    { 19 triplets, with decreasing pitch and volume }
 FOR i := 0 TO 18 DO
 WITH squareWavePtr^.triplets[i] DO
 BEGIN
 count := cnt;
 amplitude := amp;
 duration := 1;
 cnt := cnt + 60;
 amp := amp - 8;
 END;

 WITH squareWavePtr^.triplets[19] DO
 BEGIN
 count := 0;     { quit }
 amplitude := 0; { making }
 duration := 0;  { sounds }
 END;

{ let’s put up our cursor, saving the old one first...}
{ there is no ‘GetCursor’ call to complement }
{ ‘SetCursor’,}
{  so we have to dip into low memory and steal it }
 TheCurs := pointer($844);
 oldCursor := TheCurs^;

{ we need to put data into our cursor variable so we}
{ can do a ‘SetCursor’ call.  stuffing the data }
{ directly into low memory doesn’t work, because the }
{ cursor on the screen wouldn’t change until mouse }
{ was moved }
 StuffHex(ptr(@crossHairs), ’71C7408140810000');
 StuffHex(ptr(longint(@crossHairs) + 8), ‘049002A041C17777’);
 StuffHex(ptr(longint(@crossHairs) + 16), ’41C102A004900000');
 StuffHex(ptr(longint(@crossHairs) + 24), ‘4081408171C70000’);
 StuffHex(ptr(longint(@crossHairs) + 32), ’01C0208210840808');
 StuffHex(ptr(longint(@crossHairs) + 40), ’07F007F047F177F7');
 StuffHex(ptr(longint(@crossHairs) + 48), ’47F107F007F00808');
 StuffHex(ptr(longint(@crossHairs) + 56), ‘1084208201C00000’);
 StuffHex(ptr(longint(@crossHairs) + 64), ‘00070008’);
 SetCursor(crossHairs);

    { make the jaggy hole }
 holeRgn := NewRgn;
 OpenRgn;
 MoveTo(250, 180);
 LineTo(260, 226);
 LineTo(230, 252);
 LineTo(260, 242);
 LineTo(232, 278);
 LineTo(270, 242);
 LineTo(286, 304); 
 { basic hole design by Scott Boyd }
 LineTo(278, 234);
 LineTo(306, 242);
 LineTo(278, 244);
 LineTo(314, 196);
 LineTo(270, 216);
 LineTo(250, 180);
 CloseRgn(holeRgn);

{ “home” the region, prepare to add circle to }
{ the middle of the hole }
 WITH holeRgn^^.rgnBBox DO
 OffsetRgn(holeRgn, -left, -top);
 { calculate size ofhole and where the middle is }
 WITH holeRgn^^.rgnBBox DO
 BEGIN
 holeSize.h := right - left;
 holeSize.v := bottom - top;
 middlePoint.h := (right - left) DIV 2;
 middlePoint.v := (bottom - top) DIV 2;
 END;
    { figure out what size to make the circle }
 IF holeSize.h > holeSize.v THEN
 minSize := holeSize.h
 ELSE
 minSize := holeSize.v;

{ we’ll make the circle 40% of the small dimension;}
{ minSize will be the radius of the circle }
 minSize := minSize DIV 5;
 WITH middlePoint DO
 SetRect(circleRect, h - minSize, v - minSize, h + minSize, v + minSize);

    { make the circle }
 circleRgn := NewRgn;
 OpenRgn;
 FrameOval(circleRect);
 CloseRgn(circleRgn);
    { add the circle to the hole }
 UnionRgn(holeRgn, circleRgn, holeRgn);
    { we don’t need this any more... }
 DisposeRgn(circleRgn);
    { make the window manager port the current port }
 GetPort(oldPort);
 GetWMgrPort(wPort);
 SetPort(wPort);

{ ok, setup’s all finished... here’s the “main loop” }
stopIt := FALSE;
REPEAT
{ accept only mouseDown events }
IF GetNextEvent(mDownMask, theEvent) THEN
 BEGIN
 { figure out where they clicked }
 thePart := FindWindow(theEvent.where, whichWindow);
 { respond only if click on content area of window }
 IF (thePart = inContent) THEN
 BEGIN
 { Make some asynchrounous noise }
 StartSound(Ptr(squareWavePtr), buffSize, NIL);
 mouseSpot := theEvent.where;
 { position hole centered over the mouse spot }
 WITH holeRgn^^.rgnBBox DO
 OffsetRgn(holeRgn, -left, -top);
 OffsetRgn(holeRgn, mouseSpot.h - holeSize.h DIV 2, mouseSpot.v - holeSize.v 
DIV 2);
 ThisWindow := WindowPeek(whichWindow);
 { blast a hole in the structure region }
 DiffRgn(ThisWindow^.contRgn, holeRgn, ThisWindow^.contRgn);
 { blast a hole in the content region }
 DiffRgn(ThisWindow^.strucRgn, holeRgn, ThisWindow^.strucRgn);

 { calculate and paint new visible regions  }
 CalcVisBehind(WindowPeek(whichWindow), holeRgn);
 PaintBehind(windowPeek(whichWindow), holeRgn);

 {since ‘PaintBehind’ messes with the port.. }
 SetPort(wPort);
 END {IF ( thePart = inContent )... }
 ELSE
 { didn’t click in a window? }
 stopIt := TRUE;
 END; {IF GetNextEvent...}
UNTIL stopIt;
  { clean up the hole }
 DisposeRgn(holeRgn);
  {  fix the port  }
 SetPort(oldPort);
  { put the old cursor back }
 SetCursor(oldCursor);
  { get rid of the sound buffer }
 DisposPtr(Ptr(squareWavePtr));
END; {BlastIt}

 PROCEDURE Main; {Not needed for MPW}
 BEGIN
 BlastIt;
 END;

END.

Fig. 3 Creating a Code Resource in LS Pascal

Listing 2: MPW Make file for Blast

Fig. 4 Installing an FKEY in the System File

UNIT BlastStuff;

{MPW and LS Pascal Version}

INTERFACE

{ For MPW, use the following USES statement}
 USES  {$LOAD fkeyblast.dump}
      MemTypes, QuickDraw, OSIntf, ToolIntf;

{ For LS Pascal, use the following USES statement}
 USES
 ROM85;

 PROCEDURE BlastIt;
 PROCEDURE Main; {not needed for MPW}

IMPLEMENTATION

PROCEDURE BlastIt;
 CONST
 buffSize = 122; 
 { sound takes 2, 20 triplets = 120 bytes }
 VAR
 holeRgn, circleRgn : RgnHandle;
 theEvent : EventRecord;
 stopIt : Boolean;
 whichWindow : WindowPtr;
 thisWindow : WindowPeek;
 i, dur, cnt, minSize:Integer; 
 pictWidth, thePart : Integer;
 blastPict : Pichandle;
 anotherRect, circleRect, tempRect : Rect;
 mouseSpot, holeSize, middlePoint : Point;
 wPort, oldPort, tempPort : GrafPtr;
 DeskPattern : ^Pattern;
 crossHairs, oldCursor : Cursor;
 TheCurs : ^Cursor;
 squareWavePtr : SWSynthPtr;
 amp : integer;

 BEGIN

    { let’s set up sounds... }
 squareWavePtr := SWSynthPtr(NewPtr(buffSize));
 squareWavePtr^.mode := swMode; { squarewave mode }
 cnt := 400;
 amp := 150;

    { 19 triplets, with decreasing pitch and volume }
 FOR i := 0 TO 18 DO
 WITH squareWavePtr^.triplets[i] DO
 BEGIN
 count := cnt;
 amplitude := amp;
 duration := 1;
 cnt := cnt + 60;
 amp := amp - 8;
 END;

 WITH squareWavePtr^.triplets[19] DO
 BEGIN
 count := 0;     { quit }
 amplitude := 0; { making }
 duration := 0;  { sounds }
 END;

{ let’s put up our cursor, saving the old one first...}
{ there is no ‘GetCursor’ call to complement }
{ ‘SetCursor’,}
{  so we have to dip into low memory and steal it }
 TheCurs := pointer($844);
 oldCursor := TheCurs^;

{ we need to put data into our cursor variable so we}
{ can do a ‘SetCursor’ call.  stuffing the data }
{ directly into low memory doesn’t work, because the }
{ cursor on the screen wouldn’t change until mouse }
{ was moved }
 StuffHex(ptr(@crossHairs), ’71C7408140810000');
 StuffHex(ptr(longint(@crossHairs) + 8), ‘049002A041C17777’);
 StuffHex(ptr(longint(@crossHairs) + 16), ’41C102A004900000');
 StuffHex(ptr(longint(@crossHairs) + 24), ‘4081408171C70000’);
 StuffHex(ptr(longint(@crossHairs) + 32), ’01C0208210840808');
 StuffHex(ptr(longint(@crossHairs) + 40), ’07F007F047F177F7');
 StuffHex(ptr(longint(@crossHairs) + 48), ’47F107F007F00808');
 StuffHex(ptr(longint(@crossHairs) + 56), ‘1084208201C00000’);
 StuffHex(ptr(longint(@crossHairs) + 64), ‘00070008’);
 SetCursor(crossHairs);

    { make the jaggy hole }
 holeRgn := NewRgn;
 OpenRgn;
 MoveTo(250, 180);
 LineTo(260, 226);
 LineTo(230, 252);
 LineTo(260, 242);
 LineTo(232, 278);
 LineTo(270, 242);
 LineTo(286, 304); 
 { basic hole design by Scott Boyd }
 LineTo(278, 234);
 LineTo(306, 242);
 LineTo(278, 244);
 LineTo(314, 196);
 LineTo(270, 216);
 LineTo(250, 180);
 CloseRgn(holeRgn);

{ “home” the region, prepare to add circle to }
{ the middle of the hole }
 WITH holeRgn^^.rgnBBox DO
 OffsetRgn(holeRgn, -left, -top);
 { calculate size ofhole and where the middle is }
 WITH holeRgn^^.rgnBBox DO
 BEGIN
 holeSize.h := right - left;
 holeSize.v := bottom - top;
 middlePoint.h := (right - left) DIV 2;
 middlePoint.v := (bottom - top) DIV 2;
 END;
    { figure out what size to make the circle }
 IF holeSize.h > holeSize.v THEN
 minSize := holeSize.h
 ELSE
 minSize := holeSize.v;

{ we’ll make the circle 40% of the small dimension;}
{ minSize will be the radius of the circle }
 minSize := minSize DIV 5;
 WITH middlePoint DO
 SetRect(circleRect, h - minSize, v - minSize, h + minSize, v + minSize);

    { make the circle }
 circleRgn := NewRgn;
 OpenRgn;
 FrameOval(circleRect);
 CloseRgn(circleRgn);
    { add the circle to the hole }
 UnionRgn(holeRgn, circleRgn, holeRgn);
    { we don’t need this any more... }
 DisposeRgn(circleRgn);
    { make the window manager port the current port }
 GetPort(oldPort);
 GetWMgrPort(wPort);
 SetPort(wPort);

{ ok, setup’s all finished... here’s the “main loop” }
stopIt := FALSE;
REPEAT
{ accept only mouseDown events }
IF GetNextEvent(mDownMask, theEvent) THEN
 BEGIN
 { figure out where they clicked }
 thePart := FindWindow(theEvent.where, whichWindow);
 { respond only if click on content area of window }
 IF (thePart = inContent) THEN
 BEGIN
 { Make some asynchrounous noise }
 StartSound(Ptr(squareWavePtr), buffSize, NIL);
 mouseSpot := theEvent.where;
 { position hole centered over the mouse spot }
 WITH holeRgn^^.rgnBBox DO
 OffsetRgn(holeRgn, -left, -top);
 OffsetRgn(holeRgn, mouseSpot.h - holeSize.h DIV 2, mouseSpot.v - holeSize.v 
DIV 2);
 ThisWindow := WindowPeek(whichWindow);
 { blast a hole in the structure region }
 DiffRgn(ThisWindow^.contRgn, holeRgn, ThisWindow^.contRgn);
 { blast a hole in the content region }
 DiffRgn(ThisWindow^.strucRgn, holeRgn, ThisWindow^.strucRgn);

 { calculate and paint new visible regions  }
 CalcVisBehind(WindowPeek(whichWindow), holeRgn);
 PaintBehind(windowPeek(whichWindow), holeRgn);

 {since ‘PaintBehind’ messes with the port.. }
 SetPort(wPort);
 END {IF ( thePart = inContent )... }
 ELSE
 { didn’t click in a window? }
 stopIt := TRUE;
 END; {IF GetNextEvent...}
UNTIL stopIt;
  { clean up the hole }
 DisposeRgn(holeRgn);
  {  fix the port  }
 SetPort(oldPort);
  { put the old cursor back }
 SetCursor(oldCursor);
  { get rid of the sound buffer }
 DisposPtr(Ptr(squareWavePtr));
END; {BlastIt}

 PROCEDURE Main; {Not needed for MPW}
 BEGIN
 BlastIt;
 END;

END.
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Airmail 3.3.2 - Powerful, minimal email...
Airmail is an mail client with fast performance and intuitive interaction. Support for iCloud, MS Exchange, Gmail, Google Apps, IMAP, POP3, Yahoo!, AOL, Outlook.com, Live.com. Airmail was designed... Read more
Numi 3.15.1 - Menu-bar calculator suppor...
Numi is a calculator that magically combines calculations with text, and allows you to freely share your computations. Numi combines text editor and calculator Support plain English. For example, '5... Read more
Airmail 3.3.2 - Powerful, minimal email...
Airmail is an mail client with fast performance and intuitive interaction. Support for iCloud, MS Exchange, Gmail, Google Apps, IMAP, POP3, Yahoo!, AOL, Outlook.com, Live.com. Airmail was designed... Read more
Numi 3.15.1 - Menu-bar calculator suppor...
Numi is a calculator that magically combines calculations with text, and allows you to freely share your computations. Numi combines text editor and calculator Support plain English. For example, '5... Read more
TextSoap 8.4.1 - Automate tedious text d...
TextSoap can automatically remove unwanted characters, fix up messed up carriage returns, and do pretty much anything else that we can think of to text. Save time and effort. Be more productive. Stop... Read more
TextSoap 8.4.1 - Automate tedious text d...
TextSoap can automatically remove unwanted characters, fix up messed up carriage returns, and do pretty much anything else that we can think of to text. Save time and effort. Be more productive. Stop... Read more
Backblaze 4.3.0.44 - Online backup servi...
Backblaze is an online backup service designed from the ground-up for the Mac. With unlimited storage available for $5 per month, as well as a free 15-day trial, peace of mind is within reach with... Read more
Numi 3.15 - Menu-bar calculator supports...
Numi is a calculator that magically combines calculations with text, and allows you to freely share your computations. Numi combines text editor and calculator Support plain English. For example, '5... Read more
EtreCheck 3.3.3 - For troubleshooting yo...
EtreCheck is an app that displays the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support Communities to... Read more
BusyContacts 1.1.8 - Fast, efficient con...
BusyContacts is a contact manager for OS X that makes creating, finding, and managing contacts faster and more efficient. It brings to contact management the same power, flexibility, and sharing... Read more

Latest Forum Discussions

See All

The best new games we played this week
We were quite busy this week. A bunch of big mobile games launched over the past few days, alongside a few teeny surprises. There're lots of quality games to load your phone with. We've gone and picked out five of our favorites for the week. [... | Read more »
Magikarp Jump beginner's guide
Magikarp Jump is a mystifying little game. Part Tamagotchi, part idle clicker, there's not a whole lot of video game there, per se, but for some reason we can't help coming back to it again and again. Your goal is to train up a little Magikarp to... | Read more »
Goat Simulator PAYDAY (Games)
Goat Simulator PAYDAY 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: ** IMPORTANT - SUPPORTED DEVICES **iPhone 4S, iPad 2, iPod Touch 5 or better Goat Simulator: Payday is the most... | Read more »
GRID Autosport delayed until autumn
Sorry mobile racing fans -- GRID Autosport has been delayed a few months. The game is now expected to launch this fall on iOS. Feral Interactive announced that they wanted more time to work on the game's UI and overall performance before launching... | Read more »
Zombie Gunship Survival Beginner's...
The much anticipated Zombie Gunship Survival is here. In this latest entry in the Zombie Gunship franchise, you're tasked with supporting ground troops and protecting your base from the zombie horde. There's a lot of rich base building fun, and... | Read more »
Mordheim: Warband Skirmish (Games)
Mordheim: Warband Skirmish 1.2.2 Device: iOS Universal Category: Games Price: $3.99, Version: 1.2.2 (iTunes) Description: Explore the ruins of the City of Mordheim, clash with other scavenging warbands and collect Wyrdstone -... | Read more »
Mordheim: Warband Skirmish brings tablet...
Legendary Games has just launched Mordheim: Warband Skirmish, a new turn-based action game for iOS and Android. | Read more »
Magikarp Jump splashes onto Android worl...
If you're tired ofPokémon GObut still want something to satisfy your mobilePokémon fix,Magikarp Jumpmay just do the trick. It's out now on Android devices the world over. While it looks like a simple arcade jumper, there's quite a bit more to it... | Read more »
Purrfectly charming open-world RPG Cat Q...
Cat Quest, an expansive open-world RPG from former Koei-Tecmo developers, got a new gameplay trailer today. The video showcases the combat and exploration features of this feline-themed RPG. Cat puns abound as you travel across a large map in a... | Read more »
Jaipur: A Card Game of Duels (Games)
Jaipur: A Card Game of Duels 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: ** WARNING: iPad 2, iPad Mini 1 & iPhone 4S are NOT compatible. ** *** Special Launch Price for a limited... | Read more »

Price Scanner via MacPrices.net

Memorial Day savings: 13-inch Touch Bar MacBo...
B&H Photo has the 2016 Apple 13″ Touch Bar MacBook Pros in stock today and on sale for up to $150 off MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: - 13″ 2.9GHz/512GB... Read more
Apple refurbished 13-inch MacBook Airs availa...
Apple has Certified Refurbished 2016 13″ MacBook Airs available starting at $849. An Apple one-year warranty is included with each MacBook, and shipping is free: - 13″ 1.6GHz/8GB/128GB MacBook Air: $... Read more
Apple restocks refurbished 11-inch MacBook Ai...
Apple has Certified Refurbished 11″ MacBook Airs (the latest models recently discontinued by Apple), available for up to $170 off original MSRP. An Apple one-year warranty is included with each... Read more
12-inch 1.2GHz Retina MacBooks on sale for up...
B&H has 12″ 1.2GHz Retina MacBooks on sale for up to $150 off MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: - 12″ 1.2GHz Space Gray Retina MacBook: $1449.99 $150 off... Read more
15-inch 2.7GHz Silver Touch Bar MacBook Pro o...
MacMall has the 15-inch 2.7GHz Silver Touch Bar MacBook Pro (MLW82LL/A) on sale for $2569 as part of their Memorial Day sale. Shipping is free. Their price is $230 off MSRP. Read more
Free Tread Wisely Mobile App Endorsed By Fath...
Just in time for the summer driving season, Cooper Tire & Rubber Company has announced the launch of a new Tread Wisely mobile app. Designed to promote tire and vehicle safety among teens and... Read more
Commercial Notebooks And Detachable Tablets W...
Worldwide shipments of personal computing devices (PCDs), comprised of traditional PCs (a combination of desktop, notebook, and workstations) and tablets (slates and detachables), are forecast to... Read more
Best value this Memorial Day weekend: Touch B...
Apple has Certified Refurbished 2016 15″ and 13″ MacBook Pros available for $230 to $420 off original MSRP. An Apple one-year warranty is included with each model, and shipping is free: - 15″ 2.6GHz... Read more
13-inch MacBook Airs on sale for up to $130 o...
Overstock.com has 13″ MacBook Airs on sale for up to $130 off MSRP including free shipping: - 13″ 1.6GHz/128GB MacBook Air (sku MMGF2LL/A): $869.99 $130 off MSRP - 13″ 1.6GHz/256GB MacBook Air (sku... Read more
2.8GHz Mac mini available for $973 with free...
Adorama has the 2.8GHz Mac mini available for $973, $16 off MSRP, including a free copy of Apple’s 3-Year AppleCare Protection Plan. Shipping is free, and Adorama charges sales tax in NY & NJ... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Media Products - Commerce Engineerin...
Apple Media Products - Commerce Engineering Manager Job Number: 57037480 Santa Clara Valley, California, United States Posted: Apr. 18, 2017 Weekly Hours: 40.00 Job Read more
*Apple* Media Products - Commerce Engineerin...
Apple Media Products - Commerce Engineering Manager Job Number: 57037480 Santa Clara Valley, California, United States Posted: Apr. 18, 2017 Weekly Hours: 40.00 Job Read more
Best Buy *Apple* Computing Master - Best Bu...
**509643BR** **Job Title:** Best Buy Apple Computing Master **Location Number:** 001482- Apple Valley-Store **Job Description:** **What does a Best Buy Apple Read more
*Apple* Media Products - Commerce Engineerin...
Apple Media Products - Commerce Engineering Manager Job Number: 57037480 Santa Clara Valley, California, United States Posted: Apr. 18, 2017 Weekly Hours: 40.00 Job Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.