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 );
}

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

MarsEdit 3.6.8 - Quick and convenient bl...
MarsEdit is a blog editor for OS X that makes editing your blog like writing email, with spell-checking, drafts, multiple windows, and even AppleScript support. It works with with most blog services... Read more
BBEdit 11.0.3 - Powerful text and HTML e...
BBEdit is the leading professional HTML and text editor for the Mac. Specifically crafted in response to the needs of Web authors and software developers, this award-winning product provides a... Read more
Microsoft Office Preview 15.8 - Popular...
Welcome to the new and modern Microsoft Office for Mac. You will receive regular updates automatically until the official release in the second half of 2015. With the redesigned Ribbon and your... Read more
Yosemite Cache Cleaner 9.0.5 - Clear cac...
Yosemite Cache Cleaner is an award-winning general purpose tool for OS X. YCC makes system maintenance simple with an easy point-and-click interface to many OS X functions. Novice and expert users... Read more
ExpanDrive 4.3.2 - Access cloud storage...
ExpanDrive builds cloud storage in every application, acts just like a USB drive plugged into your Mac. With ExpanDrive, you can securely access any remote file server directly from the Finder or... Read more
RapidWeaver 6.0.8 - Create template-base...
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
Artlantis Studio 5.1.2.7 - 3D rendering...
Artlantis Studio is a unique and ideal tool for performing very high resolution rendering easily and in real time. The new FastRadiosity engine now lets you compute images in radiosity-even in... Read more
MacUpdate Desktop 6.0.5 - Search and ins...
MacUpdate Desktop 6 brings seamless 1-click installs and version updates to your Mac. With a free MacUpdate account and MacUpdate Desktop 6, Mac users can now install almost any Mac app on macupdate.... Read more
BitTorrent Sync 2.0.82 - Sync files secu...
BitTorrent Sync allows you to sync unlimited files between your own devices, or share a folder with friends and family to automatically sync anything. File transfers are encrypted. Your information... Read more
Google Drive 1.20 - File backup and shar...
Google Drive is a place where you can create, share, collaborate, and keep all of your stuff. Whether you're working with a friend on a joint research project, planning a wedding with your fiancé, or... Read more

Bored? MyLeisure FreeTime Maximizer Will...
Bored? MyLeisure FreeTime Maximizer Will Take Care of That! Posted by Jessica Fisher on March 5th, 2015 [ permalink ] iPhone App - Designed for the iPhone, compatible with the iPad | Read more »
New Publisher Allstar Games Heads West w...
Allstar Games has announced its first mobile title designed for western audiences, Allstar Heroes. The game will be a massive online battle arena (MOBA) that offers dozens of heroes for you to collect and pit against your opponents. As each hero has... | Read more »
RAD Boarding Review
RAD Boarding Review By Jennifer Allen on March 5th, 2015 Our Rating: :: NEARLY RADUniversal App - Designed for iPhone and iPad RAD Boarding isn’t quite one of the greats, but it has potential.   | Read more »
Presenting the International Mobile Gami...
11th Annual International Mobile Gaming Awards ceremony, hosted by actress Allison Haislip, gathered mobile game developers and publishers from around the world. They chose 13 winners out of the 93 nominations. British studio USTWO won the the Grand... | Read more »
AG Drive Review
AG Drive Review By Tre Lawrence on March 5th, 2015 Our Rating: :: FUTURISTIC STREET RACING.Universal App - Designed for iPhone and iPad Futuristic racing… interstellar style.   | Read more »
GDC 2015 – Nightmare Guardians is an Int...
GDC 2015 – Nightmare Guardians is an Interesting Hybrid of MOBA and Lane Defense Posted by Rob Rich on March 5th, 2015 [ permalink ] I have to say that lane defense (i.e. | Read more »
Overkill 3 Review
Overkill 3 Review By Tre Lawrence on March 5th, 2015 Our Rating: :: WHO'S NEXT?Universal App - Designed for iPhone and iPad Cover system gameplay in the third-person.   Developer: Craneballs Price: Free Version Reviewed: 1.1.6... | Read more »
Warner Bros. Interactive Entertainment A...
Warner Bros. has some exciting games coming down the pipe! | Read more »
GDC 2015 – Star Trek Timelines will Prob...
GDC 2015 – Star Trek Timelines will Probably Make Your Inner Trekkie Squeal With Glee Posted by Rob Rich on March 4th, 2015 [ permalink ] Any popular fictional universe has its fair share of fan fiction – where belo | Read more »
Protect Yourself from an Onslaught of Ca...
Surprise Attack Games has announced a Cat-astrophic new physics puzzler called Fort Meow! In the game, a young girl named Nia finds her grandfather’s journal which triggers an all mighty feline attack! Why do the cats want the journal? Who knows,... | Read more »

Price Scanner via MacPrices.net

Apple restocks refurbished 15-inch Retina Mac...
The Apple Store has restocked Apple Certified Refurbished 2014 15″ Retina MacBook Pros, available for up to $400 off the cost of new models. An Apple one-year warranty is included with each model,... Read more
Roundup of MacBook Air sale prices, models up...
B&H Photo has MacBook Airs on sale for up to $100 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 11″ 128GB MacBook Air: $799 100 off MSRP - 11″ 256GB MacBook Air: $999 $100... Read more
New Firstrade Mobile App Enables On-The-Go Tr...
Firstrade Securities Inc. has announced its new mobile app, which gives investors immediate access to the company’s trading platform on all mobile devices. The app was developed in-house and was... Read more
Sonnet Introduces USB 3.0 + eSATA Thunderbolt...
Sonnet has announced the launch of its new USB 3.0 + eSATA Thunderbolt Adapter for easy connectivity to USB 3.0 devices and eSATA storage, and USB 3.0 + Gigabit Ethernet Thunderbolt Adapter for easy... Read more
Apple restocks refurbished 27-inch 5K iMacs f...
The Apple Store has restocked Apple Certified Refurbished 27″ 3.5GHz 5K iMacs for $2119 including free shipping. Their price is $380 off the cost of new models, and it’s the lowest price available... Read more
Free Clean Reader Mobile App Hides Swear Word...
The new Clean Reader app, now available in the Apple App Store and Google Play, delivers the opportunity of reading any book without being exposed to profanity. By selecting how clean they want their... Read more
Kinsa Launches “Groups” App to Monitor Illnes...
Kinsa, makers of the first FDA approved app-enabled smartphone thermometer thst won the 2013 Cleveland Clinic Medical Innovation Grand Prize and recently appeared in Apple’s “Parenthood” TV... Read more
iPad: A More Positive Outlook – The ‘Book Mys...
It’s good to hear someone saying positive things about the iPad. I’ve been trying to bend my mind around how Apple’s tablet could have gone from zero to bestselling personal computing device on the... Read more
Mac Pros on sale for up to $279 off MSRP
Amazon has Mac Pros in stock and on sale for up to $279 off MSRP. Shipping is free: - 4-Core Mac Pro: $2725.87, $273 off MSRP (9%) - 6-Core Mac Pro: $3719.99, $279 off MSRP (7%) Read more
Sale! 13-inch Retina MacBook Pros for up to $...
B&H Photo has 13″ Retina MacBook Pros on sale for up to $205 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 2.6GHz/128GB Retina MacBook Pro: $1219.99 save $80 - 13″ 2.... Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
Position Opening at *Apple* - Apple (United...
…Summary** As a Specialist, you help create the energy and excitement around Apple products, providing the right solutions and getting products into customers' hands. You Read more
Position Opening at *Apple* - Apple (United...
**Job Summary** The Apple Store is a retail environment like no other - uniquely focused on delivering amazing customer experiences. As an Expert, you introduce people Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.