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

Lyn 1.5.11 - Lightweight image browser a...
Lyn is a lightweight and fast image browser and viewer designed for photographers, graphic artists and Web designers. Featuring an extremely versatile and aesthetically pleasing interface, it... Read more
NeoOffice 2014.11 - Mac-tailored, OpenOf...
NeoOffice is a complete office suite for OS X. With NeoOffice, users can view, edit, and save OpenOffice documents, PDF files, and most Microsoft Word, Excel, and PowerPoint documents. NeoOffice 3.x... Read more
LaunchBar 6.4 - Powerful file/URL/email...
LaunchBar is an award-winning productivity utility that offers an amazingly intuitive and efficient way to search and access any kind of information stored on your computer or on the Web. It provides... Read more
Remotix 3.1.4 - Access all your computer...
Remotix is a fast and powerful application to easily access multiple Macs (and PCs) from your own Mac. Features Complete Apple Screen Sharing support - including Mac OS X login, clipboard... Read more
DesktopLyrics 2.6.6 - Displays current i...
DesktopLyrics is an application that displays the lyrics of the song currently playing in "iTunes" right on your desktop. The lyrics for the song have to be set in iTunes; DesktopLyrics does nothing... Read more
VOX 2.5.1 - Music player that supports m...
VOX is a beautiful music player that supports many filetypes. The beauty is in its simplicity, yet behind the minimal exterior lies a powerful music player with a ton of features and support for all... Read more
NetNewsWire 4.0.0 - RSS and Atom news re...
NetNewsWire is the best way to keep up with the sites and authors you read most regularly. Let NetNewsWire pull down the latest articles, and read them in a distraction-free and Mac-like way. Native... Read more
MacUpdate Desktop 6.0.6 - 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
ForkLift 2.6.5 - Powerful file manager:...
ForkLift is a powerful file manager and ferociously fast FTP client clothed in a clean and versatile UI that offers the combination of absolute simplicity and raw power expected from a well-executed... Read more
Drive Genius 4.1.0 - Powerful system uti...
Drive Genius 4 gives you faster performance from your Mac while also protecting it. The award-winning and improved DrivePulse feature alerts you to hard drive issues before they become major problems... Read more

Biz Builder Delux (Games)
Biz Builder Delux 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: Ah, there's nothing like the rhythmic bustle of a burgeoning business burg... especially when you're the one building it... | Read more »
Auroch Digital is Bringing Back Games Wo...
| Read more »
Carbo - Handwriting in the Digital Age...
Carbo - Handwriting in the Digital Age 1.0 Device: iOS Universal Category: Productivity Price: $3.99, Version: 1.0 (iTunes) Description: | Read more »
Draggy Dead (Games)
Draggy Dead 1.1 Device: iOS Universal Category: Games Price: $.99, Version: 1.1 (iTunes) Description: Ditch your dead end job and take up a rewarding career in Grave Robbing today!Guide the recently deceased to a fun filled life of... | Read more »
Bad Dinos (Games)
Bad Dinos 1.0.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.0 (iTunes) Description: | Read more »
The Apple Watch isn't Great as a Fi...
| Read more »
Show the World What You See With Stre.am...
Live broadcasting is getting popular on mobile devices, which is why you can now get Stre.am, by Infinite Takes. [Read more] | Read more »
PhotoTime's 2.1 Update Adds Apple W...
The latest PhotoTime update is adding even more functionality to the handy photo organizing app. Yep, including Apple Watch support. [Read more] | Read more »
Oh My Glob! Adventure Time Puzzle Quest...
Finn and Jake are taking over D3 Go!'s popular puzzle game series in the upcoming Adventure Time Puzzle Quest. [Read more] | Read more »
Earthcore: Shattered Elements - Tips, Tr...
At first glance, Earthcore: Shattered Elements seems like a rather simple card-battling game. Once you’re introduced to skills that will change quite a bit. Even more so once you start to acquire hero cards. But it’s not so complicated that we... | Read more »

Price Scanner via MacPrices.net

OtterBox Maximizes Portability, Productivity...
From the kitchen recipe book to the boarsroom presentation, the OtterBox Agility Tablet System turns tablets into one of the most versatile pieces of handheld technology available. Available now, the... Read more
Launch of New Car App Gallery and Open Develo...
Automatic, a company on a mission to bring the power of the Internet into every car, has announced the launch of the Automatic App Gallery, an app store for nearly every car or truck on the road... Read more
Memorial Day Weekend Sale: 13-inch 1.6GHz Mac...
Best Buy has the new 13″ 1.6GHz/128GB MacBook Air on sale for $849 on their online store this weekend. Choose free shipping or free local store pickup (if available). Sale price for online orders... Read more
Memorial Day Weekend Sale: 27-inch 3.5GHz 5K...
Best Buy has the 27″ 3.5GHz 5K iMac on sale for $2099.99 this weekend. Choose free shipping or free local store pickup (if available). Sale price for online orders only, in-store prices may vary.... Read more
Sale! 16GB iPad mini 3 for $349, save $50
B&H Photo has the 16GB iPad mini 3 WiFi on sale for $349 including free shipping plus NY sales tax only. Their price is $50 off MSRP, and it’s the lowest price available for this model. Read more
Price drop on 2014 15-inch Retina MacBook Pro...
B&H Photo has dropped prices on 2014 15″ Retina MacBook Pros by $200. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.2GHz Retina MacBook Pro: $1799.99 save $200 - 15″ 2.5GHz... Read more
With a Mission to Make Mobile Free, Scratch W...
Scratch Wireless, claiming to be the world’s first truly free mobile service, has announced the availability of a new Scratch-enabled Android smartphone, the Coolpad Arise. The smartphone is equipped... Read more
First-Ever Titanium Alloy Curved iPhone 6 Scr...
One of the most common problems with mobile phones is damage to the screens. The slightest drop can cause a dreaded spider web of gashes and cracks in the glass panel surface that can cost $hundreds... Read more
Preorder new 12-inch MacBook, $10 off, save o...
Adorama has new 12″ Retina MacBooks available for preorder for $10 off MSRP including free shipping plus NY & NJ sales tax only. For a limited time, Adorama will include a free Apple USB-C to USB... Read more
Will iOS 9 Finally Bring Productivity Friendl...
Ah, the irony. From its original announcement in 2010, Apple has doggedly insisted that the iPad remain “simple,” thus arbitrarily limiting its considerable potential as a content creation and... Read more

Jobs Board

*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
Business Development Manager - *Apple* Pay...
**Job Summary** Apple Pay is seeking an experienced Business Development professional to join the Apple Pay team to develop partnerships and strategic alliances with Read more
Project Manager, *Apple* Retail New Store O...
**Job Summary** An Apple Retail New Store Openings & Remodels Project Manager is responsible for successfully managing the openings, remodels, and small works of Read more
SW QA Engineer - *Apple* TV - Apple (United...
**Job Summary** The Apple TV team is looking for experienced Quality Assurance Engineers with a passion for delivering first in class home entertainment solutions. **Key Read more
Partner Marketing Manager - *Apple* Pay - A...
**Job Summary** The Apple Pay partner marketing team is looking for a marketing manager to develop and drive US marketing programs with our financial institution Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.