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

Monolingual 1.6.4 - Remove unwanted OS X...
Monolingual is a program for removing unnecesary language resources from OS X, in order to reclaim several hundred megabytes of disk space. If you use your computer in only one (human) language, you... Read more
CleanApp 5.0 - Application deinstaller a...
CleanApp is an application deinstaller and archiver.... Your hard drive gets fuller day by day, but do you know why? CleanApp 5 provides you with insights how to reclaim disk space. There are... Read more
Fantastical 2.0 - Create calendar events...
Fantastical is the Mac calendar you'll actually enjoy using. Creating an event with Fantastical is quick, easy, and fun: Open Fantastical with a single click or keystroke Type in your event details... Read more
Cocktail 8.2 - General maintenance and o...
Cocktail is a general purpose utility for OS X that lets you clean, repair and optimize your Mac. It is a powerful digital toolset that helps hundreds of thousands of Mac users around the world get... Read more
Direct Mail 4.0.4 - Create and send grea...
Direct Mail is an easy-to-use, fully-featured email marketing app purpose-built for OS X. It lets you create and send great looking email campaigns. Start your newsletter by selecting from a gallery... Read more
jAlbum Pro 12.6 - Organize your digital...
jAlbum Pro has all the features you love in jAlbum, but comes with a commercial license. With jAlbum, you can create gorgeous custom photo galleries for the Web without writing a line of code!... Read more
jAlbum 12.6 - Create custom photo galler...
With jAlbum, you can create gorgeous custom photo galleries for the Web without writing a line of code! Beginner-friendly, with pro results Simply drag and drop photos into groups, choose a design... Read more
Lyn 1.5.9 - Lightweight image browser an...
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
Sublime Text 3080 - Sophisticated text e...
Sublime Text is a sophisticated text editor for code, markup, and prose. You'll love the slick user interface, extraordinary features, and amazing performance. Goto Anything. Use Goto Anything to... Read more
WALTR 1.0.11 - Drag-and-drop any media f...
WALTR is designed to make it easy to upload and convert any music or video file to an iPad or iPhone format for native playback. It supports a huge variety of media file types, including MP3, MP4,... Read more

Bio Inc's New Expansion is Infectin...
Bio Inc., by DryGin Studios, is the real time strategy game where you infect a human body with the worst virus your evil brain can design. Recently, the game was updated to add a whole lot of new features. Now you can play the new “Lethal”... | Read more »
The Monocular Minion is Here! Despicable...
Despicable Me: Minion Rush, by Gameloft, is introducing a new runner to the mix in their latest update. Now you can play as Carl, the prankster minion. Carl has a few new abilities to play with, including running at a higher speed from the start.... | Read more »
Dungeon of Madness (Games)
Dungeon of Madness 1.0.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.0 (iTunes) Description: Dungeon of Madness is an action game where you rotate tiles to create our own route. Help the hero by connecting the... | Read more »
Filters for iPhone (Photography)
Filters for iPhone 1.0 Device: iOS iPhone Category: Photography Price: $.99, Version: 1.0 (iTunes) Description: | Read more »
Jump'N'Shoot Attack (Games)
Jump'N'Shoot Attack 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: A mobile game for gamers! Join Louise Lightfoot, the legendary "Master of Jumping and Shooting", on her mission to save... | Read more »
Space Bounties Inc. (Games)
Space Bounties Inc. 1.4 Device: iOS Universal Category: Games Price: $1.99, Version: 1.4 (iTunes) Description: SuperGameDroid: 4/5 "Satisfying futuristic RPG combat, high replay value, and a heavy dose of nostalgia make Space... | Read more »
Gamebook: Pocket RPG (Games)
Gamebook: Pocket RPG 1.0.11 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.11 (iTunes) Description: Walk into the Land of Lanthir Lamath ruled by wicked skeletons and fight for your life in a thrilling adventure.... | Read more »
Kids Can Mix, Match, and Catch with Tata...
Tatadada MixMatch, by Tatadada Ltd, is a mobile version of the classic game of mix & match. The game uses brightly colored creatures to train your children's pattern matching skills and hand-eye coordination. It's aimed at children around age 5... | Read more »
The Trace: Murder Mystery Game (Games)
The Trace: Murder Mystery Game 1.2.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.2.0 (iTunes) Description: | Read more »
This Week at 148Apps: March 16-20, 2015
Spring Roars In At 148Apps How do you know what apps are worth your time and money? Just look to the review team at 148Apps. We sort through the chaos and find the apps you're looking for. The ones we love become Editor’s Choice, standing out above... | Read more »

Price Scanner via MacPrices.net

Logitech Says MX Master Is Its Most Advanced...
Logitech’s new MX Master Wireless Mouse incorporates the best of Logitech’s many computer mouse innovations into a striking hand-sculpted design. The company claims that the MX Master creates a new... Read more
Save up to $300 on a new Mac, $30 on an iPad,...
Purchase a new Mac or iPad at The Apple Store for Education and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free,... Read more
Apple refurbished 2014 MacBook Airs available...
The Apple Store lowered prices on Apple Certified Refurbished 2014 MacBook Airs recently, with models now available starting at $679. An Apple one-year warranty is included with each MacBook, and... Read more
Mac Notebook Evolution; A Desktop Replacement...
More often than not right from the beginning, Apple’s Macs have tended to skew toward small. The original Macs were called “compacts,”, and notwithstanding a few exceptions like the honking Big Mac... Read more
13-inch 1.4GHz/128GB MacBook Air (Apple refur...
The Apple Store has Apple Certified Refurbished 2014 13″ 1.4GHz/128GB MacBook Airs available for $759 including free shipping plus Apple’s standard one-year warranty. Their price is $240 off original... Read more
YEP! Alternative Browser for iOS Now Supports...
Pfaeffikon, Switzerland based Power App AG has announced the release of an update to their Yep! Web Browser (v1.3.0) for iOS8 iPhone and iPad. Yep! hit the App Store shortly after the release of iOS... Read more
15-inch Retina MacBook Pros on sale for up to...
B&H Photo has the new 2014 15″ Retina MacBook Pros on sale for up to $250 off MSRP for a limited time. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.2GHz Retina MacBook Pro: $... Read more
Clearance 13-inch Retina MacBook Pros availab...
B&H Photo has leftover 2014 13″ Retina MacBook Pros on sale for up to $250 off original MSRP. Shipping is free, and B&H charges NY sales tax only: - 13″ 2.6GHz/128GB Retina MacBook Pro: $1098... Read more
Clearance 2014 MacBook Airs on sale for up to...
B&H Photo has MacBook Airs on sale for up to $180 off original MSRP. Shipping is free, and B&H charges NY sales tax only: - 11″ 128GB MacBook Air: $789.99 110 off original MSRP - 11″ 256GB... Read more
Apple refurbished Time Capsules available for...
The Apple Store has certified refurbished Time Capsules available for $100 off MSRP. Apple’s one-year warranty is included with each Time Capsule, and shipping is free: - 2TB Time Capsule: $199, $100... 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
*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* Retail - Multiple Positions (US) - D...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Systems Engineer - Pre Sales, Educat...
…is responsible for proactively providing technical expertise to drive sales of Apple solutions into assigned accounts. The SE architects, validates, and assists in Read more
Sr. Technical Services Consultant, *Apple*...
**Job Summary** Apple Professional Services (APS) has an opening for a senior technical position that contributes to Apple 's efforts for strategic and transactional Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.