TweetFollow Us on Twitter

Slider FKEY
Volume Number:6
Issue Number:1
Column Tag:Pascal Procedures

Related Info: Quickdraw Window Manager

Slider FKEY

By Bill Johnson, Ron Duritsch, Cincinnati, OH

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

[Bill Johnson is an Architect who gave up the good life to become a Macintosh developer. He has written several architectural utilities for the Macintosh, and recently finished Retriever™, a database desk accessory for managing lists of information. Ron Duritsch is an Economist who can’t afford to give up the good life. Except evenings and weekends.]

Sliding Around The Guidelines

Direct interaction by users with the Macintosh screen, in the form of choosing or selecting objects they are interested in, is an important feature of the Mac’s graphical user interface. This general form of user action is described in Apple’s Human Interface Guidelines as noun-then-verb.

User selection of “objects”, or the nouns, includes many items such as icons, text, graphics, and others. One important function of the Macintosh Finder is managing icons in windows and on the desktop. Users can select an icon, or group of icons, and move them about to better manage applications and documents in a window or on the desktop.

One at a Time, Please

With the advent of larger and multiple screen use on the Mac has come a realization that objects the user can select in multiples do not include windows. Only one window can be selected or moved at any given time. We feel a simple extension of the definition of objects to include windows should be considered. Just as groups of icons can be moved for better placement on the desktop, moving groups of windows on a large screen can be just as useful. Slider is an FKEY that implements one method of doing just that.

Let It Slide

When Slider is invoked the cursor is changed to give the user feedback. The cursor takes the form of a hand (the familiar MacPaint “grabber”) over the outline of a window. At this point multiple windows can be grabbed by shift-clicking on any part of any individual window. The term “grabbed” is used here to avoid confusion with normal window “selection”, using the SelectWindow toolbox call. As each window is grabbed, it’s outline is displayed in the same manner as when clicking in it’s drag region. When the user clicks in a window using Slider, the outline of all windows currently chosen is drawn, and a sound that is correctly named and placed in the System folder is played. This group of windows can then be dragged to any position on the screen. The movement does not effect the ordering of windows from front to back.

Slider can be used effectively in any application under MultiFinder or UniFinder. Under MultiFinder, only windows in the current layer can be grabbed and moved. This is analogous to the current interface guidelines of only allowing users to select and move icons or objects in one window at any time. Slider defaults to moving all windows in the current if any one window is clicked in and immediately dragged. This provides for a very fast method of moving all windows in the current layer out of the way to expose a clearer view of windows in other layers under MultiFinder, or simply a bare desktop under UniFinder. Holding the shift key down while clicking in successive windows grabs them and adds them to a group that can be dragged. After any window or group of windows is moved beyond its initial location, Slider drops out, the pointer cursor reappears, and control is passed back to the current application.

A few other features were included to provide additional functionality. Holding the option key down while clicking in a single window grabs that window and any windows behind it in the current layer. This is useful in allowing the user to grab and drag a particular subset of windows out of view while leaving the screen position and ordering of the windows above it undisturbed.

Slider can be useful with both single and multiple screens. In default mode, dragging windows to the extreme left, right or bottom will result in at least 20 pixels of each window’s drag bar remaining on the main screen. This is to ensure that windows are not completely lost from view on a single screen. In this case, some windows that are moved must lose their positions relative to one another. Holding the command key down prevents the loss of relative window positions. In multiple screen use, holding the command key down will allow windows to be dragged to an alternate display (although we haven’t been able to test that feature). With a single screen, some windows may be lost completely from view if the command key is held down. In this case, windows out of view can be retrieved by grabbing all windows in the current layer. In all cases, dragging windows to the extreme top will leave windows positioned just below the menu bar.

Uses Of Slider

So who would need or want Slider’s features? We are guessing that more than just of few of us are annoyed at the clutter of windows that can accumulate on the desktop, especially when using several applications under MultiFinder. Moving windows one at a time is slow. Repositioning singularly moved windows to conform to their previous relative positions takes even more time. Slider provides for a very quick and efficient way to get windows out of the way all while keeping their relative positions.

The advantages of moving entire groups of windows are readily noticeable in a multiple display environment. An entire layer of windows can be quickly moved to an alternate display screen while holding on to relative window positions. Even with a minimal configuration, such as in UniFinder with a nine inch screen, the added functionality afforded by Slider’s features is useful.

Abuses Of Slider

In its current configuration Slider will move literally any window. This includes modal dialogs and windows that were meant to always be stationary. The movement of modal dialogs is not apparent to us as being useful. Usually, when a modal dialog is moved, the screen area behind it is not refreshed until the dialog is dismissed. We left this feature in for two reasons. First off, it doesn’t hurt the performance of any application that we know of. Secondly, you may find it useful where we haven’t. We invite you to recode the FKEY to bypass modal dialogs if you wish. This could be accomplished by checking the WindowKind field of the window record for inappropriate window types, although some applications use dBoxProc windows for things other than modal dialogs.

Moving an application or document window that was programmed never to be moved is a much more serious issue. In fact, it’s quite rude! You’ll find that most applications won’t care because they draw to the window’s port and only in response to update events. If the programmer of the application has followed these two rules, which are recommended by Inside Macintosh, there should be no problems. But let’s face it. Most of us break the rules from time to time. Some drawing applications use a global coordinate system, since the drawing surface (they thought) would remain stationary. Some applications will react very strangely to the movement of otherwise stationary windows. And that’s exactly why we left this feature in!

That’s Not A Virus, That’s A Feature

We found some applications to respond in fascinating ways. The command line of an excellent Mac spreadsheet application is actually made up of three windows. The part of the command line that the user types into is actually a ghost window and is not found in the window list. Surprisingly, these windows still operate correctly when moved to other screen locations.

In others, we discovered hidden windows left in for debugging purposes and who-knows-what. An easy three-dimensional drawing program that was written in an implementation of Forth has a drawing surface that appears not to be a window at all. After moving this surface with Slider, a drag region appears from under the menu bar to show that, indeed, the drawing surface is a window with a title bar. Right off the top left of this window a small white rectangle appears with a slight hint of a grow box. Expanding the grow box reveals a window with an “ok ?” prompt. Apparently this window was left in for debugging purposes and responds to different user actions.

The palettes and pattern areas of a super painting application reveal themselves to be a single inverted L-shaped window. After moving this window, however, the palette is unusable since it uses fixed global coordinates to detect mouse hits. We like to think of these not as Slider bugs, but features! You too can surprise and amuse your friends as you tear apart the windows of some of the most beloved Mac applications.

If It Ain’t Broke, Fix It

Moving otherwise stationary windows is rude if their locations are hard-coded, but occasionally it can be useful from the standpoint of adding functionality to a user interface, as in the case of unmovable tool palettes. However if you do move these, you do so at your own risk, since at times moving stationary windows will bomb an application. Any version of MacPaint, for instance, will allow you only a little fun before breaking. We found this to be rare but this is the price you are sure to pay, especially with applications that bypass normal toolbox calls or IM recommendations. At present we know of no clean way of leaving stationary windows alone, aside from simply not attempting to move them. We invite you to try and write the code that says “if the window is meant to be stationary, then don’t move it”. As a favorite professor used to say when caught in a similar dilemma, “this is left as an exercise for the reader”.

Variables and Data Structures

Before we get into the code, we need to look at the data structure that is used to store the pointers to the windows that are individually chosen with a shift-click. The variable ‘WPtrArray’ is an array of 32 window pointers, and the integer variable ‘NumWSel’ is the number of windows currently selected. Simple enough. Every time a window is clicked in, if its pointer isn’t already in the array the pointer is added to the array and ‘NumWSel’ is incremented by one. However, when we drag shift-clicked windows around the screen, we want to avoid drawing over windows that are in front of the windows being dragged. In order to do that we need to know which window is the frontmost out of our collection of shift-clicked windows. We can then call ‘ClipAbove’ using the pointer to that window to achieve this effect.

We could use a separate variable to store the pointer to the frontmost chosen window. Instead we structure the information we have by adding one more characteristic to our array of pointers; of all the pointers in the array, the one nearest the front should always be stored in the first position in the array (WPtrArray[1]). All that is required to maintain this property when inserting pointers into the pointer array is to walk down the window list starting with the pointer you want to insert. If you encounter the window pointed to by ‘WPtrArray[1]’, then the new window is above the current ‘highest’ window and belongs in ‘WPtrArray[1]’. All of these gory details are handled in the function ‘InsertWPtr’ (see below).

One last note. The toolbox call ‘ClipAbove’ is only called when ‘WPtrArray[1]’ is not equal to ‘TopWindPtr’, since there is no need to clip if the front window is being dragged. So we can kill two birds with one stone by initializing ‘WPtrArray[1]’ to ‘TopWindPtr’. If the user clicks in the menubar or desktop before any windows have been selected ‘ClipAbove’ will not be called.

The Code

Slider consists of a main procedure with no parameters (as every FKEY must) and seven procedures & functions that get called to do the dirty work. These routines are declared FORWARD so that the entrypoint of the FKEY (the main procedure ‘DragIt’) is at the beginning of the code.

PROCEDURE DragIt;

The layout of the main procedure is similar to that of a small application, with 16 lines of initialization, a mini-event loop and a few lines of dispose code.

Initialization

The first line of code gets a pointer to the front window for use in miscellaneous places. Since Slider does not change the ordering of the windows, this will not change during execution of the FKEY. The next four lines save the current port, create two regions that we need, and save the current clip region. Then call ‘GetScreenSize’ to set the dragging rectangle, and two lines later set the port to the entire window manager port. That brings us down to ‘Get3Cursors’ (see below) which sets up the cursors we will use. In the last four lines before the main loop, ‘LoadSound’ sets up a sound buffer and fills it with the contents of a sound file (if a sound file is in the System Folder), and the vars ‘DropOut’, ‘NumWSel’ and ‘WPtrArray[1]’ are initialized.

Main Loop

The main REPEAT - UNTIL statement encloses a call to GetNextEvent that is masked to only accept mouseDown events. When the mouse is clicked in a window execution passes to the inner part of the loop. In the three-statement setup, the sound is played and FindWindow is called to locate the window that the mouse was clicked in (if any). Four lines later, after being sure that the user clicked in a window, we fall into three tiers of IF statement setting up the drag region and changing the cursor. The IF statements determine which modifier keys (shift, option or none) were down when the mouse was clicked. For example, the current window region is added to ‘dragRegion’ when the shift key is down.

Now that we have set up ‘drag region’ (at least, it’s set up for now... if the shift key is down the user may continue to select windows and accumulate their StrucRgn into ‘DragRegion’ in successive passes through the loop) we set the current clipping with calls to ClipRect and ClipAbove. Remember that there is no need to call ClipAbove if the ‘highest’ window that we are to drag is equal to ‘TopWindPtr’. Then we set ‘limitRect’ and ‘slopRect’ depending on whether the command key is down. After these variables have been set up, DragGrayRgn is called to draw the gray outline of ‘DragRegion’ as it is dragged around the screen.

The remaining code inside the main loop again checks for modifier keys and moves the windows accordingly. If the shift key is down, the mouse has to have moved more than 5 pixels (hor + ver), otherwise we stay in the loop to select more windows.

Cleanup

Before returning control to the system, the the port and clipping need to be restored to their original state and regions and buffer we allocated need to be disposed of. Also, key events get flushed in case the user accidentally selects the FKEY while we were executing the code.

The first three routines after the main routine (Get3Cursors, GetScreenSize and LoadSound) are called at startup to do their work.

PROCEDURE Get3Cursors (VAR svCrs: Cursor; VAR hndCrs: Cursor; VAR scndCrs: Cursor);

Get3Cursors retrieves the current cursor from low memory, as well as stuffing hex values for the main and secondary FKEY cursors. The method was lifted from Greg Mariott’s Blast FKEY in the October ’87 MacTutor.

PROCEDURE GetScreenSize (topWind: windowPtr; VAR screenPerim: rect);

GetScreenSize uses a rather unique method to get the boundaries of the screen, since a DA or FKEY cannot use ‘Screenbits.bounds’. Instead of accessing low memory, it calls ‘NewWindow’ to create an invisible window and gets the ‘zoomed’ window size out of the ‘WStateHdl’. After this info is saved, the window is disposed of. The pointer to the front window is passed to ‘NewWindow’ in order to keep the temporary window from deactivating the front window. This ought to get points for Most Obscure Use of a Toolbox Call.

FUNCTION LoadSound (VAR SoundBuffer: Ptr; VAR sndSize: longint): boolean;

LoadSound trys to load a sound file. To allow some selection of playback rate, it will look for 2 different files. If it finds a file called ‘Sound22’, it will load it and set the sampling rate to 22 kHz. If it doesn’t find ‘Sound22’, it will look for ‘Sound11’ and if found it will load it and set the sampling rate to 11 kHz. The function will return FALSE if no sound file is found, or it TRUE if the file has been loaded. If ‘LoadSound’ returns TRUE, the pointer to the sound buffer will need to be disposed of when exiting the FKEY. Thanks to Dave Alverson for the original sound code, even if he doesn’t use Pascal.

These last four routines (InsertWPtr, SumWRgnsBelow, MoveWindBelow and MoveWindSel) are called inside the main loop.

FUNCTION InsertWPtr(HitWPtr: windowPtr; VAR PtrArray: WindArray; VAR NumWind: integer): boolean;

InsertWPtr attempts to put the pointer ‘HitWPtr’ into ‘WPtrArray’ and increment ‘NumWind’. It will return FALSE if the pointer is already in the array. It will also maintain the characteristic of the array that the first position in the array ‘WPtrArray[1]’ always contains the window pointer nearest the front.

PROCEDURE SumWRgnsBelow (StartWPtr: windowPtr; VAR DragRegion: RgnHandle);

SumWRgnsBelow returns in ‘DragRegion’ a handle to a region which is a union of the ‘strucRegion’ of all windows below ‘StartWPtr’. It is called when moving all windows (passing it the pointer to the top window) or when dragging windows with the option key down (passing it the pointer to the window clicked in).

PROCEDURE MoveWindBelow (StartWPtr: windowPtr; hor, ver: integer; dragArea: rect);

MoveWindBelow calls ‘MoveWindow’ for every window in the window list beginning with ‘StartWPtr’. The windows are moved by ‘hor’ & ‘ver’ but are not moved outside of ‘dragArea’. It is called when moving all windows (passing the pointer to the top window to ‘StartWPtr’) or when dragging windows with the option key down (passing the pointer to the window clicked in to ‘StartWPtr’).

PROCEDURE MoveWindSel (VAR PtrArray: WindArray; NumWind, hor, ver: integer; dragArea: rect);

MoveWindSel calls ‘MoveWindow’ to relocate all windows whose pointers are in ‘PtrArray’. The windows are moved by ‘hor’ & ‘ver’ but not outside of ‘dragArea’.

This Is A Hack!

We coded Slider to enter into the hack contest at MacHack ’88 conference in Ann Arbor, Michigan, where it took some measure of recognition. The idea came from members of the MACincinnati Hacker Group, an active user group and an indispensable hotbed of ideas. When confronted with the embarrassing possibility of traveling to Ann Arbor without a neat hack to evangelize, we turned to them for a solution, as well as some sound code. Thanks are in order to the group, especially Dave Alverson, Andrew Dignan and Dave Bosse, as well as to MacHack ’88 for the sponsorship of the hack contest.

Although Slider has its origins as an entrance in a hack contest, we truly had respectable intentions while writing the code. The purpose was to extend the Mac user interface by allowing windows to be grouped and moved, and it works as advertised. This is both it’s strength and weakness. What is probably needed is added functionality at the system level as opposed to the current implementation. Slider is intended to show what this type of added functionality can provide to the Mac user interface.

Source

UNIT Drag;
INTERFACE
USES
      MemTypes, QuickDraw, OSIntf, ToolIntf, SANE;
PROCEDURE DragIt;
IMPLEMENTATION
CONST
 nearInfinity  = 32000;
 SlopSize = 25;
 OutOfBounds= $8000;
 allKeyEvents  = keyDownMask + keyUpMask + autoKeyMask;
TYPE
 WindArray = ARRAY[1..32] OF WindowPtr;
{this data structure stores the window pointers that have been selected 
with the mouse. The first pointer in the array (WindArray[1]) must be 
the pointer to the selected window closest to the front window. }

PROCEDURE Get3Cursors (VAR svCrs: Cursor; VAR hndCrs: Cursor; VAR scndCrs: 
Cursor);FORWARD;
PROCEDURE GetScreenSize (topWind: windowPtr; VAR screenPerim: rect);
 FORWARD;
FUNCTION LoadSound (VAR SoundBuffer: Ptr; VAR sndSize: longint): boolean;
 FORWARD;
FUNCTION InsertWPtr(HitWPtr: windowPtr; VAR PtrArray: WindArray; VAR 
NumWind: integer): boolean; FORWARD;
PROCEDURE SumWRgnsBelow (StartWPtr: windowPtr; DragRegion: RgnHandle);
 FORWARD;
PROCEDURE MoveWindBelow (StartWPtr: windowPtr; hor, ver: integer; dragArea: 
rect);  FORWARD;
PROCEDURE MoveWindSel (VAR PtrArray: WindArray; NumWind, hor, ver: integer; 
dragArea: rect); FORWARD;

PROCEDURE DragIt;
VAR
 theEvent : EventRecord;
 WMgrPort, savePort: GrafPtr;
 HitWindPtr, topWindPtr : WindowPtr;
 currentWPeek    : windowPeek;
 WPtrArray: WindArray;
 DragRgn, ExistClipRgn    : RgnHandle;
 mousePos : Point;
 limitRect, slopRect : rect;
 screenBounds, dragLim    : rect;
 thePart, index  : integer;
 NumWSel, vMov, hMov : integer;
 mainCursor, saveCursr    : Cursor;
 secondCursor    : Cursor;
 DropOut, haveSound: boolean;
 SoundPointer    : Ptr;
 sndSize, longPos: longint;

BEGIN
 topWindPtr := FrontWindow; {does not change}
 GetPort(savePort);{save state of port/clip}
 DragRgn := NewRgn;
 ExistClipRgn := NewRgn;
 GetClip(ExistClipRgn);

 GetScreenSize (topWindPtr, screenBounds);   { get drag area size }
 dragLim := screenBounds;
 InsetRect (dragLim, 20, 0);

 GetWMgrPort(WMgrPort);
 SetPort(WMgrPort);
 
 Get3Cursors (saveCursr, mainCursor, secondCursor);
 SetCursor (mainCursor);
 haveSound := LoadSound (SoundPointer, sndSize);
 NumWSel := 0;
 DropOut := FALSE;
 WPtrArray[1] := topWindPtr;
{prevent ‘ClipAbove’ call when no windows sel}

 REPEAT
 IF GetNextEvent(mDownMask, theEvent) then
 begin
 IF (haveSound)
 then StartSound (SoundPointer, sndSize, NIL);
 mousePos := theEvent.where;
 thePart := FindWindow (theEvent.where, hitWindPtr);

 if (thePart < inSysWindow)
 then begin
 sysBeep (1);
 Dropout := TRUE;
 end
 else begin {setup of drag rgn}
 if (BitAnd(theEvent.modifiers, shiftKey) <> 0)
 then begin
 if (InsertWPtr(HitWindPtr, WPtrArray, NumWSel))
 then begin
 SetCursor (secondCursor);
 currentWPeek := WindowPeek (HitWindPtr);
 UnionRgn (currentWPeek^. StrucRgn, DragRgn, DragRgn);
 end;
 end
 else begin
 Dropout := TRUE;
 if (BitAnd(theEvent.modifiers,    optionKey) <> 0)
 then begin
 SetRectRgn (DragRgn,0,0,0,0);{ empty region of accumulated regions }
 SumWRgnsBelow (hitWindPtr, DragRgn);
 WPtrArray[1] := hitWindPtr;
 end
 else begin
 if (NumWSel = 0)
 then SumWRgnsBelow(topWindPtr, DragRgn)
 else begin
 if (InsertWPtr(HitWindPtr, WPtrArray, NumWSel))
 then begin
 SetCursor (secondCursor);
 currentWPeek := WindowPeek (HitWindPtr);
 UnionRgn (currentWPeek^.StrucRgn, DragRgn, DragRgn);
 end;
 end; { if (NumWSel > 0) }
 end;
 end;   {end setup of drag region}

 ClipRect(WMgrPort^.portRect);if (WPtrArray[1] <> topWindPtr)  
 then ClipAbove (WindowPeek (WPtrArray[1]));
 IF (BitAnd(theEvent.modifiers, cmdKey) <> 0)
 then SetRect(dragLim,-nearInfinity, -nearInfinity, nearInfinity, 
 nearInfinity);
 with dragLim do begin
 SetRect (limitRect, left, top, right, bottom);
 SetRect (slopRect, left - SlopSize, top - 45, right + SlopSize, 
 bottom + SlopSize);
 end;

 longPos := DragGrayRgn (DragRgn,
 mousePos,limitRect,slopRect,0,NIL);

 IF (longPos<>OutOfBounds) then begin
 hMov := LoWord (longPos);
 vMov := HiWord (longPos);
 IF (BitAnd(theEvent.modifiers,shiftKey)<>0)
 then begin
 IF (ABS(hMov) + ABS(vMov) > 5)    then begin
 Dropout := TRUE;
 MoveWindSel (WPtrArray,   NumWSel,hMov,vMov,dragLim);
 end;
 end
 else begin
 IF (BitAnd (theEvent.modifiers,   optionKey) <> 0)
 then MoveWindBelow (hitWindPtr, hMov, vMov, dragLim)
 else begin {default actions}
 if (NumWSel = 0)
 then MoveWindBelow  (topWindPtr, hMov,                        
 vMov, dragLim)
 else MoveWindSel  (WPtrArray, NumWSel,                        
 hMov, vMov, dragLim);
 end;
 end;
 end; {IF (longPos <> OutOfBounds)}
 end;   {if (thePart < inSysWindow)... }
 SetCursor (mainCursor);
 end;
 UNTIL Dropout;

 IF (haveSound)
 then DisposPtr (SoundPointer);
 SetPort (savePort); {restore port & clipping}
 SetClip (ExistClipRgn);
 DisposeRgn (ExistClipRgn);
 DisposeRgn (DragRgn);
 flushEvents (allKeyEvents, 0);  
 SetCursor (saveCursr); { restore cursor }
END;

PROCEDURE Get3Cursors (VAR svCrs: Cursor; VAR                  
 hndCrs: Cursor; VAR scndCrs: Cursor);
CONST
 LoMemCrsrLoc  = $844;
VAR
 CrsrPtr: ^Cursor;
BEGIN
    CrsrPtr := pointer (LoMemCrsrLoc);
    svCrs := CrsrPtr^;
    StuffHex (ptr (@hndCrs), ‘AAAA0000B030334E’ );
    StuffHex (ptr (longint (@hndCrs) + 8), ’84C954C982490249');
    StuffHex (ptr (longint (@hndCrs) + 16), ‘8D01130091000800’);
    StuffHex (ptr (longint (@hndCrs) + 24), ‘8400040082004100’);
    StuffHex (ptr (longint (@hndCrs) + 32), ‘AAAA0000B030337E’);
    StuffHex (ptr (longint (@hndCrs) + 40), ’87FF57FF83FF03FF’);
    StuffHex (ptr (longint (@hndCrs) + 48), ‘8FFF1FFF9FFF0FFF’);
    StuffHex (ptr (longint (@hndCrs) + 56), ’87FF07FF83FF41FF’);
    StuffHex (ptr (longint (@hndCrs) + 64), ‘00050007’);

    StuffHex (ptr (@scndCrs), ‘000000000030034E’ );
    StuffHex (ptr (longint (@scndCrs) + 8), ’04C904C902490249');
    StuffHex (ptr (longint (@scndCrs) + 16), ‘0D01130011000800’);
    StuffHex (ptr (longint (@scndCrs) + 24), ‘0400040002000100’);
    StuffHex (ptr (longint (@scndCrs) + 32), ‘000000000030037E’);
    StuffHex (ptr (longint (@scndCrs) + 40), ’07FF07FF03FF03FF’);
    StuffHex (ptr (longint (@scndCrs) + 48), ‘0FFF1FFF1FFF0FFF’);
    StuffHex (ptr (longint (@scndCrs) + 56), ’07FF07FF03FF01FF’);
    StuffHex (ptr (longint (@scndCrs) + 64), ‘00050007’);
END;

PROCEDURE GetScreenSize (topWind: windowPtr;                   
 VAR screenPerim: rect);
TYPE
 WStatePtr = ^WStateData;
 WStateHdl = ^WStatePtr;
VAR
 windRect : rect;
 ZoomDataHdl: WStateHdl;
 tempWindPtr: windowPtr;
BEGIN
 SetRect (windRect, 40, 0, 100, 100);
 tempWindPtr := NewWindow (nil, windRect, ‘x’,                 
 FALSE, 8, topWind, TRUE, 0);
 ZoomDataHdl := WStateHdl (WindowPeek  (tempWindPtr)^.dataHandle);
 screenPerim.left := ZoomDataHdl^^.stdState.left - 2;
 screenPerim.top := ZoomDataHdl^^.stdState.top;
 screenPerim.Right := ZoomDataHdl^^.stdState.right + 2;
 screenPerim.Bottom := ZoomDataHdl^^.stdState.bottom + 2;
 disposeWindow (tempWindPtr);
END;

FUNCTION LoadSound (VAR SoundBuffer: Ptr; VAR                  
 sndSize: longint): boolean;
 { This code trys to load a sound file. To allow some selection of playback 
rate, it will look for 2 different files.  If it finds a file called 
Sound22, it will load/play it at a sampling rate of 22 kHz. If thats 
not found, it will look for Sound11, and if found it will be played at 
11 kHz.}  
VAR
 FFSound: FFSynthPtr;
 soundRef : integer;
 rateDiv, rc: integer;
 Count, fSize  : longint;
BEGIN
 rateDiv := 1;   { assume 22 kHz sampling }
 LoadSound := FALSE;
 rc := FSOpen (‘Sound22’, 0, soundRef);
 IF (rc <> noErr)
 THEN BEGIN
 rateDiv := 2;   {set for 11 kHz playback}
 rc := FSOpen (‘Sound11’, 0, soundRef);
 END;
 IF (rc = noErr)
 THEN BEGIN
 LoadSound := TRUE;
 { get file size }
 rc := GetEOF( soundRef, fSize );
 { size of sound buffer }
 sndSize := fSize + 6;
 SoundBuffer := NewPtr (sndSize);
 FFSound := FFSynthPtr (SoundBuffer);
 FFSound^.mode := ffMode; { free form }
 { fill in the fixed binary playback rate }
 FFSound^.count := FixRatio (1, rateDiv);                      Count 
:= fSize;
 rc := FSRead (soundREf, Count, @FFSound^.waveBytes);
 rc := FSClose (soundRef);
 END;
END;

FUNCTION InsertWPtr(HitWPtr : windowPtr;
 VAR PtrArray  : WindArray;
 VAR NumWind: integer): boolean;
{IF ptr not in list, put window ptr ‘HitWPtr’ in list ‘PtrArray’ & add 
1 to ‘NumWind’ ALWAYS keep ptr to highest selected window in ‘PtrArray[1]’
 }
VAR
 ctr    : integer;
 match  : boolean;
 cWPeek : windowPeek;
 cWPtr  : WindowPtr;
 HiPtr  : WindowPtr;
BEGIN
 if (NumWind = 0)
 then begin
 NumWind := 1;
 PtrArray[1] := HitWPtr;
 InsertWPtr := TRUE;
 end
 else begin
 ctr := 0;
 REPEAT
 ctr := ctr + 1;
 match := (HitWPtr = PtrArray[ctr]);
 UNTIL (ctr = NumWind) or (match);

 if (match)
 then InsertWPtr := FALSE
 else begin
 NumWind := NumWind + 1;
 InsertWPtr := TRUE;

 HiPtr := PtrArray[1];
 cWPtr := HitWPtr;
 REPEAT
 cWPeek := WindowPeek (cWPtr);
 cWPtr := windowPtr(cWPeek^.nextWindow);
 UNTIL (cWPtr = HiPtr) or (cWPtr = NIL);
 if (cWPtr = HiPtr)
 then begin
 PtrArray[NumWind] := HiPtr;
 PtrArray[1] := HitWPtr;
 end
 else PtrArray[NumWind] := HitWPtr;
 end;
 end;
END;

PROCEDURE SumWRgnsBelow (StartWPtr: windowPtr;                 
 DragRegion: RgnHandle);
{ return in ‘DragRegion’ a region including all windows after & incl. 
window ‘StartWPtr’}
VAR
 currWPeek: windowPeek;
 PrevWPeek: windowPeek;
 currWindPtr: WindowPtr;
BEGIN
 currWindPtr := StartWPtr;
 REPEAT
 currWPeek := WindowPeek (currWindPtr);
 UnionRgn (currWPeek^.StrucRgn, DragRegion, DragRegion);
 PrevWPeek := currWPeek;
 currWindPtr := windowPtr(PrevWPeek^.nextWindow);
 UNTIL (currWindPtr = NIL);
END;

PROCEDURE MoveWindBelow (StartWPtr: windowPtr;                 
 hor, ver: integer; dragArea: rect);
{move windows -> ‘StartWPtr’ to last window in the window list by ‘hor’,’ver’
 }
VAR
 PrevWPeek: windowPeek;
 currWindPtr: WindowPtr;
 origLoc: point;
 leftBound: integer;
BEGIN
 currWindPtr := StartWPtr;
 
REPEAT
 SetPort (grafPtr(currWindPtr));
 origLoc := currWindPtr^.portrect.topleft;
 LocalToGlobal (origLoc);
 origLoc.h := origLoc.h + hor;
 origLoc.v := origLoc.v + ver;
 IF (origLoc.v < dragArea.top)
 then origLoc.v := dragArea.top;
 if (origLoc.v > dragArea.bottom)
 then origLoc.v := dragArea.bottom;
 leftBound := dragArea.left
 - GrafPtr(currWindPtr)^.portRect.right
 + GrafPtr(currWindPtr)^.portRect.left;
 if (origLoc.h < leftBound)
 then origLoc.h := leftBound;
 if (origLoc.h > dragArea.right)
 then origLoc.h := dragArea.right;
 MoveWindow(currWindPtr, origLoc.h, origLoc.v, FALSE);
 PrevWPeek := WindowPeek(currWindPtr);
 currWindPtr := windowPtr (PrevWPeek^.nextWindow);
 UNTIL (currWindPtr = NIL);
END;

PROCEDURE MoveWindSel (VAR PtrArray: 
 WindArray; NumWind: integer; hor, ver: 
 integer; dragArea : rect);
{move windows in ‘PtrArray’ by ‘hor’ & ‘ver’}

VAR
 origLoc: point;
 index  : integer;
 leftBound: integer;
BEGIN
 FOR index := 1 to NumWind DO begin
 SetPort (grafPtr(PtrArray[index]));
 origLoc := PtrArray[index]^.portrect.topleft;
 LocalToGlobal (origLoc);
 origLoc.h := origLoc.h + hor;
 origLoc.v := origLoc.v + ver;
 IF (origLoc.v < dragArea.top)
 then origLoc.v := dragArea.top;
 if (origLoc.v > dragArea.bottom)
 then origLoc.v := dragArea.bottom;
 leftBound := dragArea.left
  - GrafPtr(PtrArray[index])^.portRect.right
  + GrafPtr(PtrArray[index])^.portRect.left;
 if (origLoc.h < leftBound)
 then origLoc.h := leftBound;
 if (origLoc.h > dragArea.right)
 then origLoc.h := dragArea.right;
 MoveWindow (PtrArray[index], origLoc.h, origLoc.v, FALSE);
 end;
END;
END.    { of UNIT }
MPW MakeFile

DragIt  ƒ Drag.p.o
    Pascal Drag.p
    Link -rt FKEY=8 -m DRAGIT -t FKEY -c RSED 
      -sn “Main=Slider” 
      Drag.p.o 
 “{Libraries}”Interface.o 
      -o Slider.fkey

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Adobe Creative Cloud 2.2.0.129 - Access...
Adobe Creative Cloud costs $49.99/month (or less if you're a previous Creative Suite customer). Creative Suite 6 is still available for purchase (without a monthly plan) if you prefer. Introducing... Read more
Tower 2.2.3 - Version control with Git m...
Tower is a powerful Git client for OS X that makes using Git easy and more efficient. Users benefit from its elegant and comprehensive interface and a feature set that lets them enjoy the full power... Read more
Apple Java 2015-001 - For OS X 10.7, 10....
Apple Java for OS X 2015-001 installs the legacy Java 6 runtime for OS X 10.11 El Capitan, OS X 10.10 Yosemite, OS X 10.9 Mavericks, OS X 10.8 Mountain Lion, and OS X 10.7 Lion. This package is... Read more
Adobe Muse CC 2015 2015.0.1 - Design and...
Muse CC 2015 is available as part of Adobe Creative Cloud for as little as $14.99/month (or $9.99/month if you're a previous Muse customer). Muse CS6 is still available for purchase (without a... Read more
Adobe Illustrator CC 2015 19.1.0 - Profe...
Illustrator CC 2015 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Illustrator customer). Illustrator CS6 is still available for... Read more
Corel Painter 14.1.0.1105 - Digital art...
Corel Painter helps you create astonishing art in a variety of media. Paint with vivid oil paints, fluid water colors, and earthy charcoals. Corel Painter flawlessly recreates the tones and textures... Read more
Pacifist 3.5.4 - Install individual file...
Pacifist opens up .pkg installer packages, .dmg disk images, .zip, .tar. tar.gz, .tar.bz2, .pax, and .xar archives and more, and lets you extract or install individual files out of them. This is... Read more
Merlin Project 3.1.0.40305 - Project man...
Merlin Project is for those of you who are responsible for complex projects. Simple lists of tasks won't suffice. Good planning raises questions about the dependencies of activities on each other,... Read more
DM1 2.0 - Advanced drum machine. (Commer...
DM1 is an advanced Drum Machine. It turns your computer into a fun and creative beat making machine. Easy and fast to use, loaded with 86 superb electronic drum kits and beautiful hyper-realistic... Read more
Posterino 3.2.1 - Create posters, collag...
Posterino offers enhanced customization and flexibility including a variety of new, stylish templates featuring grids of identical or odd-sized image boxes. You can customize the size and shape of... Read more

Mazes of Karradash (Games)
Mazes of Karradash 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: The city of Karradash is under attack: the monsters of the Shadow Realms are emerging from the depths.No adventurer is... | Read more »
Battle Golf is the Newest Game from the...
Wrassling was a pretty weird - and equally great - little wressling game. Now the developers, Folmer Kelly and Colin Lane, have turned their attention to a different sport: golfing. This is gonna be weird. [Read more] | Read more »
Qbert Rebooted has the App Store Going...
The weird little orange... whatever... is back, mostly thanks to that movie which shall remain nameless (you know the one). But anyway it's been "rebooted" and now you can play the fancy-looking Qbert Rebooted on iOS devices. [Read more] | Read more »
Giant Monsters Run Amok in The Sandbox...
So The Sandbox has just hit version number 1.99987 (seriously), and it's added a lot more stuff. Just like every other update, really. [Read more] | Read more »
Fish Pond Park (Games)
Fish Pond Park 1.0.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.0 (iTunes) Description: Nurture an idyllic slice of tourist's heaven into the top nature spot of the nation, furnishing it with a variety of... | Read more »
Look after Baby Buddy on your Apple Watc...
Parigami Gold is the new premium version of the match three puzzler that includes Apple Watch support and all new content. You won't simply be sliding tiles around on your wrist, the Apple Watch companion app is an all new mini-game in itself. You'... | Read more »
Swallow all of your opponents as the big...
Eat all of the opposition and become the largest ball in Battle of Balls now available in the App Store and Google Play. Battle of Balls pits you against other opponents in real time and challenges you to eat more balls and grow larger than all of... | Read more »
PAC-MAN Championship Edition DX (Games)
PAC-MAN Championship Edition DX 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: It’s Your World. EAT IT! Get ready for more ghost chain gobbling and frantic action in PAC-MAN® CE-DX! The... | Read more »
incurve (Games)
incurve 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: Get ready for 2 different gravities Goal is to hit as many white dots on your way up.When you're touching the screen, the dots have a... | Read more »
Crossy Road has its Own Merch Store Now....
Do you like Crossy Road? I mean do you really like Crossy Road? Well then you're in luck! Hipster Whale has opened up a Crossy Road store, so you can show off your fandom via official T-shirts. [Read more] | Read more »

Price Scanner via MacPrices.net

Apple restocks refurbished Mac minis for up t...
The Apple Store has restocked Apple Certified Refurbished 2014 Mac minis, with models available starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: - 1.4GHz... Read more
13-inch 2.5GHz MacBook Pro on sale for $899,...
Best Buy has the 13″ 2.5GHz MacBook Pro available for $899.99 on their online store. Choose free shipping or free instant local store pickup (if available). Their price is $200 off MSRP. Price is... Read more
21-inch 2.9GHz iMac on sale for $1299, save $...
Best Buy has the 21″ 2.9GHz iMac on sale today for $1299.99 on their online store. Choose free shipping or free local store pickup (if available). Their price is $200 off MSRP, and it’s the lowest... Read more
Free Image Sizer 1.3 for iOS Offers Photo Edi...
Xi’An, China based G-Power has announced the release of Image Sizer 1.3 for the iPhone, iPad, and iPod touch, an important update to their free photo editing app. Image Sizer’s collection of easy to... Read more
Sale! 13″ 1.6GHz/128GB MacBook Air for $899,...
B&H Photo has the 13″ 1.6GHz/128GB MacBook Air on sale for $899 including free shipping plus NY tax only. Their price is $100 off MSRP, and it’s the lowest price available for this model. Read more
13-inch Retina MacBook Pros on sale for $100...
Best Buy has 13-inch Retina MacBook Pros on sale for $100 off MSRP on their online store. Choose free shipping or free local store pickup (if available). Prices are for online orders only, in-store... Read more
Will BMW’s i3 Electric Vehicle Be The Automo...
The German-language business journal Manager Magazin’s Michael Freitag reports that Apple and the German performance/luxury automaker Bayerishe Motoren Werke (BMW) are back at far-reaching... Read more
Sale! $250 off 15-inch Retina MacBook Pro, $2...
B&H Photo has lowered their price for the 15″ 2.2GHz Retina MacBook Pro to $1749, or $250 off MSRP. Shipping is free, and B&H charges NY sales tax only. They have the 27″ 3.3GHz 5K iMac on... Read more
Global Smartphone Market Posts 11.6% Year-Ove...
According to the latest preliminary data released from the International Data Corporation (IDC) Worldwide Quarterly Mobile Phone Tracker, smartphone vendors shipped a total of 337.2 million units... Read more
15-inch and 13-inch Retina MacBook Pros on sa...
B&H Photo has 15″ & 13″ Retina MacBook Pros on sale for up to $180 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.2GHz Retina MacBook Pro: $1819 save $180 - 15″ 2.... Read more

Jobs Board

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