TweetFollow Us on Twitter

More Event Trapping
Volume Number:6
Issue Number:6
Column Tag:XCMD Corner

Related Info: Event Manager Window Manager

More on Event Trapping

By Donald Koscheka, Ernst & Young, MacTutor Contributing Editor

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

This issue marks the second anniversary of this column and I thought it might be a good time to share my Macintosh wish list with you. My list doesn’t contain the usual items that you might expect of a programmer - a faster CPU, more RAM, larger disk space because I know these things are coming; our technology just keeps getting better and better.

I have only one wish and it is a rather strange one: I wish that the Macintosh will once again become a personal computer in the manner of its great ancestor, the Apple ][. Because of the Apple ][, we no longer think of computers as threatening monoliths, rather they are regarded as benign if not beneficial tools of civilization.

The Apple ][ accomplished this in two ways; it was affordable and “user friendly”. Affordability, it turns out, is the keystone to user friendliness. Apple wanted the Apple ][ to be a computer for the masses, not only would the hardware have to be cheap, but also the software, the training and the service. Every aspect of the Apple ][ experience was intended to be “friendly” -- from locally accessible support groups to the schematics that were published in the manuals so that real dilettantes could service their own equipment.

By contrast, the Macintosh has become the “Institutional Apple”. Apple no longer seems concerned with the individual successes of its users and everything about the Macintosh seems geared towards corporate sales and megalithic installations. The “user-friendly” infrastructure that Apple so carefully fostered with the Apple ][ has evaporated. Let me explain with a story:

Recently, my Mac IIcx had a main logic board failure because one of those little jumpers on the board came loose (how that happened remains an endless source of speculation -- the computer is never moved about). I was shocked to discover that a new main logic board (we used to call them “mother boards”) would cost me $600 and that’s with a trade-in allowance!

While the average institution may not balk at a $600 repair cost, I could not help but feel that Apple’s service policy borders on usury. Think about it. My computer fails because its designers did not anticipate a particular failure mode. Although the machine is barely six months old, the factory does not warrant such repairs. My computer is down, I’m out and no where can I find a sympathetic ear, the entire system is simply indifferent to the needs of one despondent user.

What the Macintosh has lost is that “sense of peopleness” that we had with the Apple ][. I know because I worked in a computer store during the heyday of the Apple ][. Once, a despondent customer called to explain that he had installed a card “backwards” in his Apple and it shorted something on the motherboard (we call them main logic boards now) blowing a hole through the board! I quoted him the price of a new motherboard (about $400 plus trade-in) and that that poor man just broke down in tears. I told him to bring the computer in and I’d see what I could do. Being an electrical engineer, and knowing that the Apple ][ was a simple two-layer board, I methodically re-wired the blown out traces with some ordinary hook-up wire. Remarkably, the board worked (no chips were blown). I called the customer and told him the good news - that the damage was just cosmetic and that, while looking like a high school science project, the board worked fine. The cost: $50.00; the customer: ecstatic.

Those days are gone. I called half a dozen computer stores and they all quoted me between $600 and $700. No one suggested my bringing it in, that they would have a look at it. No one suggested that I might get a discount, even after asking for one. The attitude was just so institutional - your computer is broken and now you’re going to have to pay to get it working again. Some maintenance maven at Apple is sure to say that this situation cannot be helped - that the Macintosh has just gotten too complicated for the ordinary service technician and that this is a small price to pay for technological excellence. I say hogwash (but I mean worse) - if the Mac is that complicated, then make it simpler to repair. And if ordinary service technicians can’t fix it, then get extraordinary ones. Heavens knows, we’re paying them enough; computer repair people charge almost twice as much as auto mechanics. Yet the latter have to know more about cars to do a good job, and few car repairs last weeks as is often the case with computers.

I can’t help but feel bitter about this whole experience, mainly because Apple seems so indifferent to its “personal” users. Perhaps this insensitivity comes with being a multi-billion dollar company. Too bad, I somehow wanted to believe that Apple would be different.

My story does have a happy ending in that I did find a sympathetic technician, Mike Cerrone of the Computer Factory, Stamford, CT, who worked with me in isolating the problem to the little jumper. In so doing, he saved me nearly $600 in repairs. People like Mike are what this business is all about and I hope his bedside manner comes back into style.

More on Event Trapping

Two months ago I introduced the concept of intercepting the event trap in Hypercard. This technique could be used to add custom controls, external windows, key click filters and the like to a stack. I seem to have struck a nerve among the Hypercard programming community because several readers have “wired” asking for more information. I will show you how to maintain lists in windows that are external to Hypercard. This work is based on the March ’90 issue and you may want to refer back to it.

This XCMD contains a lot of source code, so I’m just publishing the highlights, the rest of the code is available from MacTutor.

Listing 1 contains the main code for the XCMD, “floating list.c”. We accept commands of the form:

`1

    get FloatingList( COMMAND, <WINDOW, parameters> )

where <window, parameters> are optional and COMMAND is one of the following:

INSTALL: installs the patch to get next event and initialize the external window system. You should invoke this command only once during a stack session.

REMOVE: removes the patch to getnextevent. call only when you are done with the windowing system.

OPEN: open a new window and add the items passed to the list. The window is opened with the name provided in the window parameter. This window will have a list associated with it. Open takes several parameters:

Parameter 3: the rectangle for this window

Parameter 4: the window type.

Parameter 5: 1 if you want the window visible, 0 otherwise.

Parameter 6: data to put into the list. Currently lists are implemented as single column multi-row lists but you can modify the code in do_open() to fit your needs (see listing 2, “Window Commands.c” ).

`2

    put FloatingList( “OPEN”, windowname, “50 10 300 210”, ¬
    “DOCUMENT”, 1, card field “your list name” ) into it

The window types and command names are stored in string# resources with the following format: Each line contains the name followed by a comma followed by the number (token) that codes for that name. For example, the install command is coded as: Install, 0. The source disk contains a sample stack with these resources.

CLOSE: close a window by name. The window must have been previously opened using the window command.

SHOW: show the window whose name is passed.

HIDE: hide the window whose name is passed.

I’ve left room for three more commands: add, delete and clear to allow you to add an item to the list, to delete an item and to clear an item. These will be the subject of a future column. For now, you pass a complete list to window on open.

Each command is handled by a routine in “Window Commands.c” (listing 2).

This system allows you to open windows external to Hypercard and to track events within those windows. This is a powerful but easy-to-use system. How it’s done is really quite simple as I will explain.

The information for the external windows is stored off a structure called “wdGlobals” for window globals. This structure is allocated and intialized as a non-relocatable block in the system heap by do_init() (see listing 2). If the block can be allocated, we then load the event trap patch in as a resource of type ‘EXEC’ and then move it to the system heap. At this point the event trap is ready to start responding to events outside of the Hypercard window.

External windows are created using the Open command and the code is implemented in the routine do_open() (the parser that this routine uses was covered in the March issue). Once allocated, windows are referenced via a structure that I call the ‘post’ named in honor of the post-it note, the greatest invention since cellophane tape.

The structure of the post record is depicted in figure 1. The doubly-linked list allows us to have as many windows open as memory will allow. Note that I allocate the window memory in the post structure in the field “window store”. This is so that the window record gets allocated in the system heap out of Hypercard’s way. The windowPtr is a standard window manager structure which should point to the window store subrecord. List is a standard list handle. Name is the name of the window (called out separately for convenience - this field is redundant with the name field in the window record itself). Is_color determines whether this is a color window and id is currently not used but you can use it to assign unique ids to each window.

Figure 1. Structure of the Post record.

The post structure gets stored in the list field of the wdGlobals structure. Now this structure acts as our global memory since we need to access the structure from both the XCMD and from the event patch itself. In March, I showed you how to save such data in the system resource file. I’ve since had a change of heart and now choose to store the structure in one of the extra fields in the trap header. The routine, SetWindowHeader (Listing 4) places our record at byte offset 10 (decimal) from the start of the patch. If our patch was patched, offset 10 may not point to the correct structure in the future. For this reason, I set the signature of the patch to ‘isme’. Before accessing the window globals, I check to make sure that the patch has the correct signature. If so, then the window globals at offset 10 are valid. This may seem klunky but it’s a heck of a lot better than messing with the system resource file which seems to have a mind of its own.

The patch was described in a previous article so I won’t go into great detail. Note that for most purposes, it performs as a standard event loop. The main difference is that we first look at the event to see if it belongs to one of the “post” notes. If so, we handle it and inform Hypercard that no event occurred on the last invocation of getnextevent. If the event is not for one of our windows, we pass it back to Hypercard and let it decide what to do with it. The code in listing 2 is a “tail patch” in that we first invoke the original trap and then take some sort of action. While many programmers frown on tail-patches, this one does work and we do need to know what the most recent event is in order to process it.

Happy hacking and I hope you find this article interesting. We will explore this area further in future issues.

Listing 1:

/********************************/
/* File: Floating List.c  */
/* */
/* Window with drawing commands  */
/* */
/* Paramters:    */
/* param0 = command*/
/* param1 = name of the window*/
/* param2..n= window parameters  */
/* INSTALL*/
/*  OPEN*/
/* CLOSE*/
/* SHOW */
/* HIDE */
/* ADDITEM*/
/*  DELETEITEM   */
/* CLEAR*/
/*  REMOVE*/
/* */
/* Out: */
/* Responds to the given command*/
/* ----------------------------  */
/* © 1989 Donald Koscheka */
/* All Rights Reserved    */
/********************************/

#include“WindowUtils.h”
#include<HyperXCMD.h>
#include“WindowCommands.h”

pascal void main( paramPtr )
 XCmdBlockPtr  paramPtr;
{
 wdGlobalsPtr  windP;
 short  theToken;
 Str31  command;
 Str31  str;
 char   name[256];
 
 /*** empty is the default answer  ***/
 paramPtr->returnValue = 0L;
 
 /*** (1) Parse for the command type ***/
 theToken = matchToken( paramPtr->params[0], 1020 );

 /*** (2) Now do whatever the command requires***/
 if( theToken >= 0 ){
 name[0] = ‘\0’;
 
 if( paramPtr->params[1] )
 strcat( (char *)&name, *(paramPtr->params[1]) );
 
 windP = (wdGlobalsPtr)GetWindowHeader( EVENT_TRAP );
 
 if( theToken == INSTALL_CMD && !windP )
 do_init();
 else
 if( windP )
 switch( theToken ){
 case OPEN_CMD:
 do_open( name, paramPtr, windP );
 break;
 case CLOSE_CMD:
 do_close( name, paramPtr, windP );
 break;
 case SHOW_CMD :
 do_show( name, paramPtr, windP );
 break;
 case HIDE_CMD :
 do_hide( name, paramPtr, windP );
 break;
 case ADD_CMD :
 do_additem( name, paramPtr, windP );
 break;
 case DELETE_CMD :
 do_deleteitem( name, paramPtr, windP );
 break;
 case CLEAR_CMD : 
 do_clear( name, paramPtr, windP );
 break;
 case REMOVE_CMD :
 do_remove( paramPtr, windP );
 break;
 default : 
 break;
 } /* token switch */
 }
 paramPtr->returnValue = 0L;
}
Listing 2:

/********************************/
/* File: WindowCommands.c */
/* */
/* Window with drawing commands  */
/* */
/* Out: */
/* Responds to the given command*/
/* */
/* Result codes are returned*/
/* thusly:*/
/* */
/* 0 == noErr    */
/* -1== unknown error*/
/* -2..-n == error in parameter  */
/* ----------------------------  */
/* © 1989 Donald Koscheka */
/* All Rights Reserved    */
/********************************/

#include“WindowUtils.h”
#include<ListMgr.h>
#include<HyperXCMD.h>
#include<HyperUtils.h>

#include“WindowCommands.h”
#include“ParseCommands.h”

long  do_init()
/***********************
* Install the special event
* handling code needed to make
* the window system a guest 
* of Hypercard.
*
* Note that the handlers go
* in the application heap
* so that they die a natural
* death at the end of the 
* Hypercard session
*
* returns a handle to the event
* patch (which is locked in the 
* application heap).
*
* 11.26.89 Installs the global
* data in the system resource fork
* also, move the event handler into the
* system heap so that it stays
* alive on us.
***********************/
{
 wdGlobalsPtr  windP;
 Handle event_handler;    
 Handle sysPlace;
 void   *oldTrap;
 long   hSiz;
 
 windP = (wdGlobalsPtr)sys_alloc( (long)sizeof( wdGlobals ));
 if( windP ){
 /*** 11.26.89   ***/
 event_handler = GetResource( ‘EXEC’, EVENT_EXEC );

 if( validHandle( event_handler  ) ){
 
 /*** copy our handler into the system heap***/
 hSiz = GetHandleSize( event_handler );
 
 if( sysPlace = sys_alloc( hSiz ) ){
 BlockMove( *event_handler, sysPlace, hSiz );

 oldTrap = (void *)NGetTrapAddress( EVENT_TRAP, ToolTrap);

 NSetTrapAddress( sysPlace, EVENT_TRAP, ToolTrap );
 
 SetWindowHeader( EVENT_TRAP, (void *)windP );
 
 /*** need to save off oldTrap where ***/
 /*** everyone can find it***/
 windP->evtProc  = sysPlace;
 windP->oldTrap  = oldTrap;
 windP->list   = 0L; /*no windows in our list yet*/
 windP->userData = 0L;  
 /*** initialize this for the user ***/
 }
 }/*** if validHandle( event_handler ) ***/
 }
}

long  do_remove( paramPtr, windP )
 XCmdBlockPtr  paramPtr;
 wdGlobalsPtr  windP;
/***********************
* Remove the event patch
* so that normal event processing can
* occur.
*
* paramPtr->params[1] is a
* handle to the routine to 
* remove.  This routine is
* a standard code type resource
* and we store the old trap
* address at 10(entrypoint)
*
* -- 11.26.89 --
* Our patch is in if windP is
* valid AND its wdProc field is
* valid.  wdProc contains a
* handle to the event patch.
***********************/
{
 Ptr    patch  = (Ptr)windP->evtProc;
 postHand post_it= windP->list;
 postHand next_it;
 
 /*** unload the patch  ***/
 NSetTrapAddress( windP->oldTrap, EVENT_TRAP, ToolTrap);
 
 /*** unload all data in any open windows***/
 while( post_it ){
 next_it = (*post_it)->next;
 remove_post( windP, post_it );
 post_it = next_it;
 }
 
 /*** unload patch & globals***/
 DisposPtr( patch );
 DisposPtr( (Ptr)windP );
}

long  do_open( name,  paramPtr, windP )
 char   *name;
 XCmdBlockPtr  paramPtr;
 wdGlobalsPtr  windP;
/***********************
* open a window with the 
* given name and add it to the
* list.
*
* Open accepts the following 
* parameters:
*
* param1: name (must be unique)
* param2: rect
* param3: procID (windowtype)
* param4: visible
* param5: List data
*
* if the window is already open
* do nothing but bring it to the 
* front.
*
* Windows automatically get a list
* assigned to them.
*
***********************/
{
 Rect   theRect;
 short  visible;
 short  theProc;
 postHand postH;
 WindowPtrtheWind;
 postPtrpp;
 SysEnvRectheWorld;
 Str255 pName;
 
 ListHandle theList;
 Point  cSize;
 Rect   dataBounds;
 FontInfo theFont;
 char   *start;
 char   *end;
 Cell   theCell;
 short  colCnt;
 short  rowCnt;
 short  displayRows;
 short  displayCols;
 short  rowNum = 1;
 
 /*** parse the parameter list***/
 if( postH = Find_Window_By_Name( windP->list, name ) ){
 ShowWindow( (*postH)->wind );
 BringToFront( (*postH)->wind );
 return( 0 );
 }
 
 parseRect( paramPtr->params[2], &theRect );
 
 theProc = (short)matchToken( paramPtr->params[3], WINDOW_TYPES );
 
 visible = (short)parseNum( *(paramPtr->params[4] ) );

 /*** if all the parameters are    ***/
 /*** valid, do the open, otherwise***/
 /*** alert the user.***/
 pName[0] = ‘\0’;
 strcat( (char *)pName, (char *)name );
 CtoPstr( (char *)pName );
 
 postH = (postHand)NewSysHandle( (long)sizeof( post ) );
 if( !validHandle( postH ) )
 return( -1 );
 
 MoveHHi( postH );
 HLock( postH );
 HNoPurge( postH );
 
 add_post( windP, postH );
 
 pp = *postH;

 theWind = NewWindow( &(pp->wStore), &theRect, pName, visible, theProc, 
IN_FRONT, GO_AWAY, 0L );
 SetPort( theWind );
 
 pp->wind = theWind;
 pp->list = 0L;
 pp->id = 0;
 pp->is_color= FALSE;
 
 /*** NOTE: this approach doesn’t work for a color***/
 /*** mac that has it’s monitor set to 2-color!!!***/
 /** NEED TO DETERMINE WHETHER WE HAVE 2 COLORS IN***/
 
 if( SysEnvirons( 1, &theWorld ) == noErr )
 if( theWorld.hasColorQD )
 pp->is_color = TRUE;
 
 (pp->name)[0] = ‘\0’;
 strcat( (char *)(pp->name), name );
 
 /*** ADD A LIST TO THIS WINDOW ***/
 TextFont( 3 );
 TextSize( 12 );
 GetFontInfo( &theFont );
 cSize.v = theFont.ascent + theFont.descent + theFont.leading;

 /*** set the rectangle to local coordinates ***/
 theRect.bottom  = theRect.bottom - theRect.top;
 theRect.right   = theRect.right - theRect.left;
 theRect.top   = 2;
 theRect.left  = 2;
 cSize.h = theRect.right - theRect.left;

 displayRows = (theRect.bottom - theRect.top) / cSize.v;
 displayCols = (theRect.right - theRect.left) / cSize.h;
 
 theRect.bottom = theRect.top + (displayRows * cSize.v);
 theRect.right  = theRect.left + (displayCols * cSize.h );
 
 dataBounds.top  = 0;
 dataBounds.left = 0;
 dataBounds.bottom = 1;
 dataBounds.right  = 1;
 
 /*** adjust rectangle for scroll bars ***/
 theRect.right -= 15 * ((displayRows > 1 )? 1 : 0 );
 theRect.bottom -= 15 * ((displayCols > 1 )? 1 : 0 );
 
 theList = LNew( &theRect, &dataBounds, cSize, 0, theWind, TRUE, TRUE, 
displayCols > 1, displayRows > 1 );

 pp->list = theList;
 rowCnt = 0;
 
 /*** (*) Put the data into the cells***/          
 LDoDraw( FALSE, theList );
 if( paramPtr->params[5] ){
 HLock( paramPtr->params[5] );
 end = start = *(paramPtr->params[5] );
 
 for( colCnt = 0; colCnt < dataBounds.right; colCnt++ ){
 theCell.h = colCnt;
 
 /*** add rows until no more data ***/
 while( *start ){
 theCell.v = rowCnt++;
 while( *end != ‘\0’ && *end != CR )
 end++;
 
 rowNum = LAddRow( 1, rowCnt, theList );
   LSetCell( start, (short)(end-start), theCell, theList);
 start = end++;
 }
 }
 HUnlock( paramPtr->params[5] );
 }
 LDoDraw( TRUE, theList );
 
 /*** select the default cell ***/
 theCell.v = theCell.h = 0;
 LSetSelect( TRUE, theCell, theList );
 
 return( noErr );
}
 
long  do_close( name, paramPtr, windP )
 char   *name;
 XCmdBlockPtr  paramPtr;
 wdGlobalsPtr  windP;
/***********************
* given the name of a window,
* look it up in the window list
* and then try to close it
*
***********************/
{
 postHand postH;
 
 /*** find the window ***/
 if( postH = Find_Window_By_Name( windP->list, name  ) )
 remove_post( windP, postH );
}
 
long  do_show( name, paramPtr, windP )
 char   *name;
 XCmdBlockPtr  paramPtr;
 wdGlobalsPtr  windP;
/***********************
*
*
***********************/
{
 postHand postH;
 
 /*** find the window ***/
 if( postH = Find_Window_By_Name( windP->list, name ) ){
 ShowWindow( (*postH)->wind );
 BringToFront( (*postH)->wind );
 }
}
 
long  do_hide( name, paramPtr, windP )
 char   *name;
 XCmdBlockPtr  paramPtr;
 wdGlobalsPtr  windP;
/***********************
*
*
***********************/
{
 postHand postH;
 
 /*** find the window ***/
 if( postH = Find_Window_By_Name( windP->list, name ) )
 HideWindow( (*postH)->wind );
}
 
long  do_additem( name, paramPtr, windP )
 char   *name;
 XCmdBlockPtr  paramPtr;
 wdGlobalsPtr  windP;
/***********************
* add an item to the end of 
* the windows list list 
*
* param[2] is the item to add.
***********************/
{
 Handle data;
 postHand postH;
 
 /*** find the window ***/
 if( postH = Find_Window_By_Name( windP->list, name ) ){
 }
}

long  do_deleteitem( name, paramPtr, windP )
 char   *name;
 XCmdBlockPtr  paramPtr;
 wdGlobalsPtr  windP;
/***********************
* remove an item from the window
* list 
* 
* param[2] contains the number
* of the item to remove
* 
***********************/
{
 postHand postH;
 
 if( postH = Find_Window_By_Name( windP->list, name ) ){
 }
}

long  do_clear( name, paramPtr, windP )
 char   *name;
 XCmdBlockPtr  paramPtr;
 wdGlobalsPtr  windP;
/***********************
* erase the contents of a window
* and deallocate all it’s drawing
* objects.
***********************/
{
 postHand postH;
 GrafPtroldPort;
 
 /*** find the window ***/
 if( postH = Find_Window_By_Name( windP->list, name ) ){
 
 GetPort( &oldPort );
 SetPort( (*postH)->wind );
 EraseRect( &((*postH)->wind)->portRect );
 InvalRect( &((*postH)->wind)->portRect );
 SetPort( oldPort );
 }
}
Listing 3:

/************************************/
/* File: EventPatch.c*/
/* */
/* Patch to get next event*/
/* to allow us to intercept events */
/* from Hypercard. */
/* */
/* check to see if we get the event*/
/* if not, pass it back on, */
/* otherwise, handle the event and */
/* return a null event to Hypercard*/
/* */
/* The real getnextevent will unbias*/
/* the stack parameters so we need */
/* to save them off before we call */
/* the real trap */
/* */
/* The Boolean result of GetNextEvt*/
/* will be at 0(A7) immediately  */
/* after calling the real trap*/
/* */
/* If we took the event, then all we*/
/* need do is set the result of  */
/* GetNextEvent to false. */
/* */
/* Note that we are post-processing*/
/* the trap here.*/
/* --------------------------------*/
/* ©1989 Donald Koscheka  */
/* All Rights Reserved    */
/************************************/

#include<HyperXCMD.h>
#include“WindowUtils.h”
#include“WindowCommands.h”
#include<SetUpA4.h>

/*** NOTE: you can have no stack frames in the ***/
/*** intercept since this is a stack based trap***/
/*** That is to say, the stack is already biased***/
/*** correctly for the trap -- any local variables ***/
/*** must be declared as statics below, no locals***/
/*** are allowed in main. ***/

static  void*returnAddress;
static  EventRecord*theEvent;
static  short    evtMask;
static  short    haveEvt;
static  WindowPtrwhichWindow;
static  Rectr;
static  short    windoPart;
static  void*oldA4;
static  wdGlobalsPtr windP;
static  ProcPtr  oldTrap;
static  postHand thePost;

/********************************************/
/* Important note: */
/* */
/* Patch behaved badly with modaldialg and   */
/* the scripting window due to the fact that*/
/* both of these facilities require a valid  */
/* A4 register.  The fix was to save off the*/
/* old value of A4 before getting the new    */
/* value of A4.  */
/* */
/* Since oldA4 is a “pseudo global” (ie its  */
/* referenced off our value of A4, we must   */
/* first setup A4 before saving the old      */
/* value off.    */
/********************************************/

void main(){
 asm{
 Move.l A4, D0   ; we might need to save the old A4
 Move.l A0, A4   ; pointer to our globals for later.
 Move.l D0, oldA4; note that oldA4 is referenced off A4
 
 Move.l 10(A0), windP ; handle to the window header data
 
 Move.l (A7)+, returnAddress; save the real return address...
 Move.l (A7), theEvent  ; save the event record pointer
 Move.w 4(A7), evtMask  ; and the event mask
 }
 
 oldTrap = windP->oldTrap;
 
 asm{   ; left the stack intact for the call
 Move.l oldTrap, A0
 Jsr    (A0)
 Move.b (A7), haveEvt; did we get an event?
 }
 
 whichWindow = FrontWindow();
 
 if( windP && haveEvt && (((WindowPeek)whichWindow)->windowKind != dialogKind) 
 ){
 switch( theEvent->what ){
 case mouseDown:
 
 windoPart = FindWindow( theEvent->where, &whichWindow);
 
 if( (windoPart >= inContent ) ){
 /*** need to temporarily unpatch GetNextEvent***/
 /*** for the mouse tracking stuff because some***/
 /*** tracking calls also call getNextEvent!!!***/
 NSetTrapAddress( windP->oldTrap, EVENT_TRAP, ToolTrap);

 switch ( windoPart ){
 case inGoAway:
 if( thePost = find_post( windP, whichWindow))
 if (TrackGoAway( whichWindow, 
 theEvent->where) ){
 remove_post( windP, thePost );
 haveEvt = 0;
 }
 break;
 case inDrag:
 /*** calculate the drag rect ***/
 /*** need a non-A5 way of getting***/
 /*** the screen dimensions.***/
 r.top  = 0;
 r.left = 0;
 r.bottom= 1024;
 r.right = 1024;
 
 DragWindow( whichWindow, theEvent->where, &r );
 haveEvt = 0;
 break;
 case inGrow:
 /*** MyGrowWindow( whichWindow, theEvent->where         );***/
 /*** redraw the contents ***/
 haveEvt = 0;
 break;
 case inContent:
 if (whichWindow != FrontWindow() ){
 SelectWindow( whichWindow );
 haveEvt = 0;
 }
 else 
 if ( thePost = find_post( windP, whichWindow ) ){
 GlobalToLocal( &theEvent->where );
 if( LClick( theEvent->where, 
 theEvent->modifiers,
 (*thePost)->list ) ) ;
 haveEvt = 0;
 }
 break;
 default: 
 break;
 }/* end switch FindWindow */
 
 /*** now re-install the patch***/
 NSetTrapAddress( windP->evtProc, EVENT_TRAP, ToolTrap);

 } /*** if mouse down in our window ***/
 break;
 case mouseUp:
 if( thePost = find_post( windP, FrontWindow() ) ){
 haveEvt = 0; 
 }
 break;
 case keyDown:
 case autoKey:
 break;
 case activateEvt:
 whichWindow = (WindowPtr)theEvent->message;
 if ( find_post( windP, whichWindow ) )
 if ( theEvent->modifiers & activeFlag ){
 r= (*whichWindow).portRect;
 r.top = r.bottom;
 r.left = r.left;
 InvalRect( &r );
 haveEvt = 0;
 }
 break;
 case updateEvt: 
 whichWindow = (WindowPtr)theEvent->message;
 if( thePost = find_post( windP, whichWindow ) ){
 SetPort( whichWindow );
 BeginUpdate( whichWindow );
 UpdateWindow( thePost , whichWindow->visRgn );
 DrawControls( whichWindow );
 EndUpdate( whichWindow );
 haveEvt = 0;
 }
 break;
 default: 
 break;
 } /* switch theEvent->what */
 } /* if haveEvt */
 
 asm{ 
 Move.b haveEvt, (A7)
 Move.l returnAddress, A0
 Move.l oldA4, A4
 Jmp    (A0)
 }
}

UpdateWindow( postH, visRgn )
 postHand postH;
 RgnHandlevisRgn;
/******************
* put your update code here
******************/
{
 ListHandle theList;
 
 theList = (*postH)->list;
 
 if( theList )
 LUpdate( visRgn, theList );
}
Listing 4:

/********************************/
/* File: WindowUtils.c    */
/* */
/* Once the object is parsed, it*/
/* is added to the draw list for*/
/* the window.   */
/* */
/* Eventually need to match */
/* multiple tokens so that we */
/* can have parameters such as:  */
/* BOLD&ITALIC&OUTLINE    */
/* ----------------------------  */
/* © 1989 Donald Koscheka */
/* All Rights Reserved    */
/********************************/

#include“WindowUtils.h”
#include<HyperUtils.h>
#include<HyperXCMD.h>

void  *GetWindowHeader( theTrap )
 short  theTrap;
/************************
* Given the trap id, return
* the item stored at offset 
* $0A off the entry point.  We
* can use this location to store
* a handle to data used by the
* trap handler
*
* The resource type in the header
* (isme) will be at 4(A0) if this
* is our patch.
*
*************************/
{
 void *tProc = (void *)NGetTrapAddress( theTrap, ToolTrap);
 void *header = 0L;
 
 asm{
 Move.l A0, -(sp)
 Move.l tProc, A0
 
 Move.l 4(A0), D0
 Cmp.l  #’isme’,D0
 Bne    @1
 
 Move.l 10(A0), header
@1 Move.l (sp)+, A0
 }
 
 return( header );
}

void    SetWindowHeader( theTrap, theHeader )
 short  theTrap;
 void *theHeader;
/************************
* Given the trap id, place the handle
* in the location at  
* offset $0A off the entry point.  We
* can use this location to store
* a handle to data used by the
* trap handler
*
*************************/
{
 void *tProc= (void *)NGetTrapAddress( theTrap, ToolTrap);
 
 asm{
 Move.l A0, -(sp)
 Move.l tProc, A0
 Move.l #’isme’, 4(A0); save a copy of entry point
 Move.l theHeader, 10(A0)
 Move.l (sp)+, A0
 }
}

postHandFind_Window_By_Name( postList, name )
 postHand postList;
 char   *name;
/***********************
* Given the name of a window
* search the post list until
* that post is found and 
* then return a handle to
* that post or NIL if the window
* is not found.
*
***********************/
{
 postHand myPost = postList;
 
 while( myPost ){
 if( strcmp( (*myPost)->name, name ) == 0 )
 return( myPost ); 
 else
 myPost = (*myPost)->next;
 }
 
 return( 0L );   
}

void  add_post( wdPtr,  postIt )
 wdGlobalsPtr  wdPtr;
 postHand postIt;
/***********************
* Add the current window 
* (postIt) to our list.
*
* basically, the item gets
* added to the end of the list
*
***********************/
{
 postHand myList = wdPtr->list;
 
 (*postIt)->next = (*postIt)->last = 0L;
 
 if( !myList )   /*** no items in the list yet     ***/
 wdPtr->list = postIt;
 else{
 while( (*myList)->next )
 myList = (*myList)->next;
 
 (*postIt)->last = myList;
 (*myList)->next = postIt;
 }
 
}

void  remove_post( wdPtr, postIt )
 wdGlobalsPtr  wdPtr;
 postHand postIt;
/***********************
* remove the requested window
* from the window list and
* deallocate all of its data
*
***********************/
{
 postHand myList = wdPtr->list;
 postHand lastPost;
 postHand nextPost;

 
 if( validHandle( (Handle)postIt ) && validHandle( (Handle)myList ) ){
 
 if( postIt == myList )
 wdPtr->list = (*postIt)->next;
 else{
 while( myList )
 if( myList == postIt ){
 lastPost= (*postIt)->last;
 nextPost= (*postIt)->next;
 
 if( lastPost )
 (*lastPost)->next = nextPost;
 
 if( nextPost )
 (*nextPost)->last = lastPost;
 
 break; 
 }
 else
 myList = (*myList)->next;
 }

/*** if postit is valid, we can deallocate its structures***/
 if( (*postIt)->list )
 LDispose( (*postIt)->list );
 CloseWindow( (*postIt)->wind );
 TrashHandle( (Handle)postIt );
 }
}

postHandfind_post( windP, which )
 wdGlobalsPtr  windP;
 WindowPtrwhich;
/*******************************
* if the window pointer passed in
* corresponds to a window in our list
* of post-it windows, then return the
* post that owns that window.
*
* if no match, return NIL
*******************************/
{
 postHand thePost= windP->list;
 
 while( thePost ){
 if( (*thePost)->wind == which )
 return( thePost );
 else
 thePost = (*thePost)->next;
 }
 
 return( 0L );
}

 
AAPL
$102.47
Apple Inc.
+2.71
MSFT
$44.88
Microsoft Corpora
+0.80
GOOG
$526.54
Google Inc.
+5.70

MacTech Search:
Community Search:

Software Updates via MacUpdate

EyeTV 3.6.6 - Watch and record TV on you...
EyeTV brings a rich TV experience to your Mac. Watch live TV on your Mac. Pause, rewind, and record whenever you want. EyeTV gives you powerful control over what you watch and how you watch it. Put... Read more
RapidWeaver 6.0 - Create template-based...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
NTFS 12.0.39 - Provides full read and wr...
Paragon NTFS breaks down the barriers between Windows and OS X. Paragon NTFS effectively solves the communication problems between the Mac system and NTFS, providing full read and write access to... Read more
RestoreMeNot 2.0.3 - Disable window rest...
RestoreMeNot provides a simple way to disable the window restoration for individual applications so that you can fine-tune this behavior to suit your needs. Please note that RestoreMeNot is designed... Read more
Macgo Blu-ray Player 2.10.9.1750 - Blu-r...
Macgo Mac Blu-ray Player can bring you the most unforgettable Blu-ray experience on your Mac. Overview Macgo Mac Blu-ray Player can satisfy just about every need you could possibly have in a Blu-ray... Read more
Apple iOS 8.1 - The latest version of Ap...
The latest version of iOS can be downloaded through iTunes. Apple iOS 8 comes with big updates to apps you use every day, like Messages and Photos. A whole new way to share content with your family.... Read more
TechTool Pro 7.0.5 - 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
PDFKey Pro 4.0.2 - Edit and print passwo...
PDFKey Pro can unlock PDF documents protected for printing and copying when you've forgotten your password. It can now also protect your PDF files with a password to prevent unauthorized access and/... Read more
Yasu 2.9.1 - System maintenance app; per...
Yasu was originally created with System Administrators who service large groups of workstations in mind, Yasu (Yet Another System Utility) was made to do a specific group of maintenance tasks... Read more
Hazel 3.3 - Create rules for organizing...
Hazel is your personal housekeeper, organizing and cleaning folders based on rules you define. Hazel can also manage your trash and uninstall your applications. Organize your files using a... Read more

Latest Forum Discussions

See All

Swap Heroes (Games)
Swap Heroes 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: **Half price for a limited time only** Swap Heroes is a casual turn-based strategy adventure. Form a group of heroes and guide them... | Read more »
Ghost Blade (Games)
Ghost Blade 1.1 Device: iOS Universal Category: Games Price: $4.99, Version: 1.1 (iTunes) Description: Get the most outstanding 3D Action Game from App Store NOW! For those who dare pursue dreams. Masterpiece of Yu Shi Game ---China... | Read more »
Fiete – A Day on a Farm Review
Fiete – A Day on a Farm Review By Amy Solomon on October 21st, 2014 Our Rating: :: A MEMORABLE EXPERIENCEUniversal App - Designed for iPhone and iPad Fiete – A day on a farm in an interactive app for young children full of... | Read more »
Tilt to Live: Gauntlet’s Revenge is Almo...
Tilt to Live: Gauntlet’s Revenge is Almost Here Posted by Jessica Fisher on October 21st, 2014 [ permalink ] One Man Left has announced the official release date of Tilt to Live: Gauntlet’s Re | Read more »
Sago Mini Monsters Celebrates Halloween...
Sago Mini Monsters Celebrates Halloween with Fun Costumes and Special Treats. Posted by Jessica Fisher on October 21st, 2014 [ permal | Read more »
Inferno 2 Review
Inferno 2 Review By Andrew Fisher on October 21st, 2014 Our Rating: :: TWIN STICK GOODNESSUniversal App - Designed for iPhone and iPad With tight controls and awesome, stark visuals, Inferno 2 is loads of fun.   | Read more »
Clips Review
Clips Review By Jennifer Allen on October 21st, 2014 Our Rating: :: CONVENIENT PASTINGUniversal App - Designed for iPhone and iPad Making copying and pasting more powerful than usual, Clips is a great way to move stuff around.   | Read more »
MonSense Review
MonSense Review By Jennifer Allen on October 21st, 2014 Our Rating: :: ORGANIZED FINANCESiPhone App - Designed for the iPhone, compatible with the iPad Organize your finances with the quick and easy to use, MonSense.   | Read more »
This Week at 148Apps: October 13-17, 201...
Expert App Reviewers   So little time and so very many apps. What’s a poor iPhone/iPad lover to do? Fortunately, 148Apps is here to give you the rundown on the latest and greatest releases. And we even have a tremendous back catalog of reviews; just... | Read more »
Angry Birds Transformers Review
Angry Birds Transformers Review By Jennifer Allen on October 20th, 2014 Our Rating: :: TRANSFORMED BIRDSUniversal App - Designed for iPhone and iPad Transformed in a way you wouldn’t expect, Angry Birds Transformers is a quite... | Read more »

Price Scanner via MacPrices.net

Select MacBook Airs $100 off MSRP, free shipp...
B&H Photo has 2014 a couple of MacBook Airs on sale for $100 off MSRP. Shipping is free, and B&H charges NY sales tax only. They also include free copies of Parallels Desktop and LoJack for... Read more
13-inch 2.5GHz MacBook Pro on sale for $100 o...
B&H Photo has the 13″ 2.5GHz MacBook Pro on sale for $999.99 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more
Strong iPhone, Mac And App Store Sales Drive...
Apple on Monday announced financial results for its fiscal 2014 fourth quarter ended September 27, 2014. The Company posted quarterly revenue of $42.1 billion and quarterly net profit of $8.5 billion... Read more
Apple Posts How-To For OS X Recovery
OS X 10.7 Lion and later include OS X Recovery. This feature includes all of the tools you need to reinstall OS X, repair your disk, and even restore from a Time Machine backup. OS X Recovery... Read more
Mac OS X Versions (Builds) Supported By Vario...
Apple Support has posted a handy resource explaining which Mac OS X versions (builds) originally shipped with or are available for your computer via retail discs, downloads, or Software Update. Apple... Read more
Deals on 2011 13-inch MacBook Airs, from $649
Daily Steals has the Mid-2011 13″ 1.7GHz i5 MacBook Air (4GB/128GB) available for $699 with a 90 day warranty. The Mid-2011 13″ 1.7GHz i5 MacBook Air (4GB/128GB SSD) is available for $649 at Other... Read more
2013 15-inch 2.0GHz Retina MacBook Pro availa...
B&H Photo has leftover previous-generation 15″ 2.0GHz Retina MacBook Pros now available for $1599 including free shipping plus NY sales tax only. Their price is $400 off original MSRP. B&H... Read more
Updated iPad Prices
We’ve updated our iPad Air Price Tracker and our iPad mini Price Tracker with the latest information on prices and availability from Apple and other resellers, including the new iPad Air 2 and the... Read more
Apple Pay Available to Millions of Visa Cardh...
Visa Inc. brings secure, convenient payments to iPad Air 2 and iPad mini 3as well as iPhone 6 and 6 Plus. Starting October 20th, eligible Visa cardholders in the U.S. will be able to use Apple Pay,... Read more
Textkraft Pocket – the missing TextEdit for i...
infovole GmbH has announced the release and immediate availability of Textkraft Pocket 1.0, a professional text editor and note taking app for Apple’s iPhone. In March 2014 rumors were all about... Read more

Jobs Board

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
*Apple* Solutions Consultant (ASC) - Apple (...
**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 / Business Analyst, WW *Appl...
…a senior project manager / business analyst to work within our Worldwide Apple Fulfillment Operations and the Business Process Re-engineering team. This role will work Read more
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Position Opening at *Apple* - Apple (United...
…customers purchase our products, you're the one who helps them get more out of their new Apple technology. Your day in the Apple Store is filled with a range of Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.