TweetFollow Us on Twitter

Debugging Code Res
Volume Number:6
Issue Number:3
Column Tag:Programmer's Forum

Related Info: Control Manager

Debugging Code Resources

By Bryan Waters, Casselberry, FL

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

Developing and Debugging Control Definition Procedures

An application I was working on recently required a control that operated similar to the way the date and time is set in the alarm clock desk accessory. So I set out to write my own control definition procedure. Everything was going great, until I tried to use it. It didn’t work. Now, I can use TMON with the best, but I don’t program in C just so I can sit down and calculate offsets for all my structures, and track down variables on the stack. In order to use THINK C’s source level debugger, I had to embed my CDEF in my test application. This article describes exactly how I did this, and provides a framework for which any type of definition procedure ( WDEFs, LDEFs, MDEFs, and MBDFs ) can be tested and thoroughly debugged using a debugger like THINK C’s.

Control Definition Procedures

A control definition procedure, for those of you who don’t already know, is a resource of type ‘CDEF’, which contains the code to draw and manipulate a specific style of control. The Macintosh comes with two default CDEFs. These are the button CDEF, which has resource ID of 0, and the scroll bar CDEF, which is resource ID 1. The procID argument to NewControl, is determined by a combination of the resource ID, and the variation code. The algorithm for calculating the procID is as follows:

resourceID * 16 + variation code

This allows for up to 16 variations of a control. The button CDEF, has three variations, the button, the check box, and the radio button. These have variation codes of 0, 1, and 2. Using this information, the procID for the radio button would be 0*16+2 or 2. The scroll bar CDEF does not have any variations, so its procID would be 1*16+0, or 16. In our example the CDEF has an ID of 2, so that its procID would be 32. When NewControl is called, the resource ID and the variation code is backed out of the procID, and then it loads the CDEF with that resource ID, and calls it with the appropriate variation code. The interface to the CDEF is defined as follows:

/* 1 &/

pascal long mycdef(varCode,myControl,message,param)
int varCode ;
ControlHandle myControl ;
int message ;
long param ;

The varCode parameter is the variation code of the particular control.  Since our control 
won’t have any variations, we can ignore this parameter.  The second parameter is the control 
handle itself.  The last parameter is used for passing extra information associated with 
a specific message.  The message parameter tells our CDEF what the control manager wants 
us to do.  The messages are defined as follows:

/* 2 */

enum{
 drawCntl,
 testCntl,
 CalcCRgns,
 initCntl,
 dispCntl,
 posCntl,
 thumbCntl,
 dragCntl,
 autoTrack
} ;

Then initCntl, and the dispCntl messages, are for initialization, and cleanup respectively. Our control uses these messages to allocate and initialize data storage, and to dispose of it. The control manager uses the testCntl message to request a partCode for a mouseDown in a control. The drawCntl message is used in conjunction with a partCode to cause the part to be drawn. Initially a partCode of 0 is passed in param, which tells our CDEF to draw the whole control. When a CDEF receives a drawCntl message, it must do several checks first. First it must check the cntrlVisible field of the control, to see if we need to draw the control at all. Then the cntrlHilite field must be checked to see if part of the control must be hilited. The cntrlHilite field specifies a partCode to hilite on the control, 0 for the whole control, or 255 to inactivate the control. The autoTrack message is sent to track a mouseDown event in the control. Upon initialization, the actionProc field of the control should be set to -1 to indicate that there is a default “Tracking” procedure. When a mouse down first occurs in a control, the Control Manager first call the CDEF with testCntl, which returns a partCode, and then calls the CDEF with autoTrack, passing the partCode in param. The autoTrack procedure should handle whatever hiliting needs to be done, plus whatever other tasks need to be specific to the control. The CalcCRgns message should be handled by building the region of the control into the RgnHandle passed in param. The top byte of param should be cleared first, to clear bit flags that the control manager sets. The dragCntl, posCntl, and thumbCntl messages are not required to implement our control. For more information on these see chapter 10, of Inside Macintosh Vol. I.

Figure 1. Testing CDEFs

Debugging Code Resources

The following is a description of the method used for using THINK C’s source debugger to debug code resources:

• first create a dummy code resource with the same interface as the code resource to be debugged. This dummy code resource will do nothing but a GetResource on an unused type. Then it will use the first long word of this resource to make a pascal call to this address using the same parameters as it was called with.

• Include the code resource to be debugged in the test application’s project.

• In the beginning of the test application, first allocate a long word size handle. Then get the address of the main routine of the code resource, and store it in the handle. Now we do an add resource of the same unused type as our dummy code resource uses.

• The rest of the application proceed to use the code resource as it normally would. At this point you will be able to compile and debug your code resource under the debugger in THINK C.

One of the things to watch for while using this technique is that when a code resource is being used under the debugger, if your code resource uses globals, you will be referencing off of A5. Code resources reference globals off of A4 in THINK C. This normally would cause no problem, except that THINK C does not set up A4 pointing to your code resource globals. This must be done by the RememberA0(), SetupA4() sequence done in the beginning of the listing of the example CDEF. At the end of the CDEF, the RestoreA4( ) restores the old value of A4.

Date/Time Control

Our control was written in an attempt to provide a method for entering the date and time conveniently, and having a control that was portable to other programs and not embedded inside of the program. The CDEF for this control is provided on this issues source code disk and can be ported into your own program, using Resedit. The way it is used, is as follows:

Ex.3 

 install the control in you window or dialog
 while( i don’t want to quit yet ) {
        getnextevent
        if( mouseDown ) {
             FindControl( )
             partCode = TrackControl( )
             HiliteControl( ourControl, partCode )
        }
 }

To call this control definition procedure use procId 32, and make sure that the CDEF resource 2, is either in your applications resource fork or your system file. When the control first comes up it uses the current system date and time, but this can be changed by creating the control as invisible, and referencing off of the contrlData field to set the NEW_DATE_TIME field of the controls data. Then make the control visible and it will use the date and time that was just set. The control uses military time only ( it would be a nice addition to add support for standard time ), and since it only provides two digits for the year, is only good until 1999. To get the date out of the control, again you will need to reference off of the contrlData structure to the CONTROL_DATE_TIME field, before the control is disposed of. The files used in this article are listed here:

date_cdef.c - code for date/time cdef

date_convert.c - DateTimeRec to character string conversion routine

test_cdef_main.c - Control test application

debug_test_cdef_main.c - Control test main routine used

used to debug the cdef under the debugger.

dummy_cdef.c - dummy control defProc used to call actual cdef embedded in application.

Good luck!

Listing:  date_cdef.c

/******** System includes ********/
#include <Quickdraw.h>
#include <ControlMgr.h>
#include <MemoryMgr.h>
#include <OSUtil.h>
#include <FontMgr.h>
#include <SetupA4.h>
/**********************************/

/******** defines ********/
#define NULL 0L
#define CONTROL_WINDOW    ( (*my_control)->contrlOwner )
#define CONTROL_VISIBLE   ( (*my_control)->contrlVis )
#define CONTROL_HILITE    ( (*my_control)->contrlHilite )
#define CONTROL_VALUE( (*my_control)->contrlValue )
#define CONTROL_MIN( (*my_control)->contrlMin )
#define CONTROL_MAX( (*my_control)->contrlMax )
#define CONTROL_TITLE( (*my_control)->contrlTitle )
#define CONTROL_RECT (**(DATE_TIME_CONTROL_HDL)\
        ((*my_control)->contrlData)).control_rect
#define CONTROL_RECT_LEFT (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).control_rect.left
#define CONTROL_RECT_TOP  (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).control_rect.top
#define CONTROL_RECT_RIGHT(**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).control_rect.right
#define CONTROL_RECT_BOTTOM (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).control_rect.bottom
#define CONTROL_DATE_TIME (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).date_time
#define CONTROL_FONT_WIDTH(**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).font_width
#define CONTROL_FONT_HEIGHT (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).font_height
#define CONTROL_ITEM_RECT (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).item_rect
#define CONTROL_ITEM_HILITE (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).item_hilite
#define CONTROL_ITEM_UPDATE (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).item_update
#define CONTROL_CHAR_POS  (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).char_point
#define CONTROL_CHAR_ARY  (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).character
#define CONTROL_HILITED   (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).item_hilited
#define CONTROL_LST_HILITED (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).last_hilite
#define NEW_CLIP (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).new_clip
#define OLD_CLIP (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).old_clip
#define DE_BOUNCER (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).de_bouncer
#define NUM_DAYS (**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).num_days
#define NEW_DATE_TIME(**(DATE_TIME_CONTROL_HDL)\
 ((*my_control)->contrlData)).new_date_time_rec
#define MONTH_PART_CODE   1
#define DAY_PART_CODE2
#define YEAR_PART_CODE    3
#define HOUR_PART_CODE    4
#define MINUTE_PART_CODE  5
#define UP_ARROW 6
#define DOWN_ARROW 7
#define CHARACTER_OFFSET  0
#define DATE_TIME_OFFSET  8
#define TOP_DOWN_MARGIN   4
#define NUM_CHARS13
#define NUM_PARTS8
#define CONTROL_FONT systemFont
#define CONTROL_FONT_SIZE 0
#define CONTROL_FONT_STYLE0
#define DELAY    7
/**********************************/

/******** Global variables ********/
/* control data structure */
typedef struct {
 DateTimeRec date_time ;  /* current time */
 Rect item_rect[NUM_PARTS] ;/* item rect array */
 int font_width ;/* font width */
 int font_height ; /* font height */
 int item_hilite[NUM_PARTS] ; /* item hilite array */
 int item_update[NUM_PARTS] ; /* item update array */
 Point char_point[NUM_CHARS] ;/* pen pos. array for chars */
 int character[NUM_CHARS] ; /* character array */
 int item_hilited ;/* current item hilited */
 int last_hilite ; /* last item hilited */
 RgnHandle old_clip ;/* scratch rgnhandle */
 RgnHandle new_clip ;/* scratch rgnhandle */
 Rect control_rect ; /* control rect */
 int de_bouncer ;/* up/down arrow click delay */
 int num_days[12] ;/* days in month array */
 DateTimeRec new_date_time_rec ;   /* new date time */
} DATE_TIME_CONTROL, *DATE_TIME_CONTROL_PTR, **DATE_TIME_CONTROL_HDL 
;
/**********************************/

/******** Subroutine prototypes ********/
pascal long main( int, ControlHandle, int, long ) ;
void doDrawControl( long, ControlHandle ) ;
long doTestControl( long, ControlHandle ) ;
void doCalcCRgns( RgnHandle, ControlHandle ) ;
void doInitControl( ControlHandle ) ;
void doTrackControl( int, ControlHandle ) ;
void Date2Chars( DateTimeRec *, int * ) ;
/****************************************/

/******** Bitmap for arrows ***************/
char bits[2*18] = {
0x3F, 0x80, 
0x40, 0x40, 
0x84, 0x20, 
0x8E, 0x20, 
0x9F, 0x20, 
0xBF, 0xA0, 
0x8E, 0x20, 
0x8E, 0x20, 
0x80, 0x20, 
0x80, 0x20, 
0x8E, 0x20, 
0x8E, 0x20, 
0xBF, 0xA0, 
0x9F, 0x20, 
0x8E, 0x20, 
0x84, 0x20, 
0x40, 0x40, 
0x3F, 0x80 } ;
/****************************************/


/******** CDEF 2 call with proc id 16*2 32 ********/
pascal long main( varCode, my_control, message, param )
int varCode ;
ControlHandle my_control ;
int message ;
long param ;
{
 GrafPtr old_port ;
 PenState pen_state ;
 int i ;
 Point p ;
 long result ;

 /* Set up a4 */
 RememberA0( ) ;
 SetUpA4( ) ;
 
 /* Initialize function result */
 result = 0 ;
 
 /* Initial setup */
 if( ( (**my_control).contrlData == NULL ) && ( message != initCntl ) 
) {
 return result ;
 }else if( (**my_control).contrlData != NULL ) {
 HLock( (**my_control).contrlData ) ;
 }
 HLock( my_control ) ;
 
 /* Save port information */
 GetPort( &old_port ) ;
 SetPort( CONTROL_WINDOW ) ;
 GetPenState( &pen_state ) ;
 PenNormal( ) ;
 
 /* Set the font */
 TextFont( CONTROL_FONT ) ;
 TextFace( CONTROL_FONT_STYLE ) ;
 TextSize( CONTROL_FONT_SIZE ) ;
 
 /* Check for control being repositioned, or date being set manually 
by program */
 if( message != initCntl ) {
 /* If rects do not match */
 if( ( (*my_control)->contrlRect.top != CONTROL_RECT_TOP ) || ( (*my_control)->contrlRect.left 
!= CONTROL_RECT_LEFT ) ) {
 /* Update item rects */
 for( i = 0; i<NUM_PARTS;i++ ) {
 OffsetRect( &CONTROL_ITEM_RECT[i], 
    (*my_control)->contrlRect.left -
  CONTROL_RECT_LEFT, (*my_control)->contrlRect.top -
       CONTROL_RECT_TOP ) ;
 }
 /* Now update character rects */
 p.h=(*my_control)->contrlRect.left - CONTROL_RECT_LEFT ;
 p.v = (*my_control)->contrlRect.top - CONTROL_RECT_TOP ;
 for( i = 0; i<NUM_CHARS;i++ ) {
 AddPt( p, &CONTROL_CHAR_POS[i] ) ;
 }
 OffsetRect( &CONTROL_RECT, 
      (*my_control)->contrlRect.left-CONTROL_RECT_LEFT,
      (*my_control)->contrlRect.top-CONTROL_RECT_TOP) ;
 }
 /* Now check to see if time has changed */
 if( ( NEW_DATE_TIME.year != CONTROL_DATE_TIME.year ) ||
 ( NEW_DATE_TIME.month != CONTROL_DATE_TIME.month ) ||
 ( NEW_DATE_TIME.day != CONTROL_DATE_TIME.day ) ||
 ( NEW_DATE_TIME.hour != CONTROL_DATE_TIME.hour ) ||
   ( NEW_DATE_TIME.minute != CONTROL_DATE_TIME.minute ) ) {
 CONTROL_DATE_TIME = NEW_DATE_TIME ;
 Date2Chars( &CONTROL_DATE_TIME, CONTROL_CHAR_ARY ) ;
 doDrawControl( 0, my_control ) ;
 }
 }

 /* Now handle control messages */
 switch( message ) {
 case initCntl:  /* Initialize control */
 doInitControl( my_control ) ;
 break ;
 case drawCntl:  /* draw the control */
 if( CONTROL_VISIBLE ) {
 doDrawControl( param, my_control) ;
 }
 break ;
 case testCntl:  /* test mouse location */
 result = doTestControl( param, my_control ) ;
 break ;
 case calcCRgns: /* calc controls region */
 param = param & 0x00FFFFFF ; /* Mask out hi byte */
 doCalcCRgns( (RgnHandle)param, my_control ) ;
 break ;
 case autoTrack: /* track mouse hits */
 doTrackControl( param, my_control ) ;
 break ;
 case dispCntl:  /* dispose control data */
 DisposeRgn( OLD_CLIP ) ;
 DisposeRgn( NEW_CLIP ) ;
 DisposHandle( (**my_control).contrlData ) ;
 break ;
 case posCntl:   /* Handled by default */
 case dragCntl:
 break ;
 }
 
 /* Restore grafport */
 SetPenState( &pen_state ) ;
 SetPort( old_port ) ;
 
 /* Unlock handle to data to minimize heap fragmentation */
 if( (**my_control).contrlData != NULL ) {
 HUnlock( (**my_control).contrlData ) ;
 }
 
 /* Restore a4 */
 RestoreA4( ) ;
 
 return result ;
}
void doInitControl( my_control )
ControlHandle my_control ;
{
 FontInfo font_info ;
 Rect box ;
 int i ;
 char **hdl ;
 
 /* Allocate and lock data storage */
 (**my_control).contrlData = NewHandle( sizeof( DATE_TIME_CONTROL ) ) 
;
 if( (**my_control).contrlData == NULL ) {
 return ;
 }
 HLock( (**my_control).contrlData ) ;
 
 /* Set up controls rect and init data area */
 SetRect( &CONTROL_RECT, 0, 0, 140, 24 ) ;
 OffsetRect( &CONTROL_RECT, (*my_control)->contrlRect.left, 
 (*my_control)->contrlRect.top ) ;
 (*my_control)->contrlAction = (ProcPtr)-1 ;
 OLD_CLIP = NewRgn( ) ;
 NEW_CLIP = NewRgn( ) ;
 
 /* Initialize time structure */
 GetTime( &CONTROL_DATE_TIME ) ;
 Date2Chars( &CONTROL_DATE_TIME, CONTROL_CHAR_ARY ) ;
 NEW_DATE_TIME = CONTROL_DATE_TIME ;
 
 /* Now init character rects */
 /* Get the font information */
 GetFontInfo( &font_info ) ;
 
 /* Get height and width */
 CONTROL_FONT_WIDTH = font_info.widMax - 6 ;
 CONTROL_FONT_HEIGHT = font_info.ascent ;
 
 /* Calculate item rects now */
 box = CONTROL_RECT ;
 box.top = box.top + TOP_DOWN_MARGIN ;
 box.bottom = box.top + CONTROL_FONT_HEIGHT ;
 box.left = CONTROL_RECT_LEFT + DATE_TIME_OFFSET ;
 box.right = box.left + 2*CONTROL_FONT_WIDTH + CHARACTER_OFFSET ;
 /* Init char points */
 for( i=0;i<NUM_CHARS;i++){
 CONTROL_CHAR_POS[i].v = box.bottom ;
 }
 box.bottom += 2 ;
 
 i = 0 ;
 /* Calculate total rect */
 CONTROL_ITEM_RECT[0] = CONTROL_RECT ;
 
 /* Calculate month rect and character points */
 CONTROL_ITEM_RECT[MONTH_PART_CODE] = box ;
 CONTROL_CHAR_POS[i++].h = box.left ;
 CONTROL_CHAR_POS[i++].h = box.left + CHARACTER_OFFSET + CONTROL_FONT_WIDTH 
;
 
 /* Now calc position for first slash */
 CONTROL_CHAR_POS[i++].h = box.right + CHARACTER_OFFSET ;
 
 /* Calculate day rect and character points */
 OffsetRect( &box, ( CONTROL_FONT_WIDTH + 2*CHARACTER_OFFSET + ( box.right 
- box.left ) ),0 ) ;
 CONTROL_ITEM_RECT[DAY_PART_CODE] = box ;
 CONTROL_CHAR_POS[i++].h = box.left ;
 CONTROL_CHAR_POS[i++].h = box.left + CHARACTER_OFFSET + CONTROL_FONT_WIDTH 
;
 
 /* Now calc position for second slash */
 CONTROL_CHAR_POS[i++].h = box.right + CHARACTER_OFFSET ;
 
 /* Calculate year rect and character points */
 OffsetRect( &box, ( CONTROL_FONT_WIDTH + 2*CHARACTER_OFFSET + ( box.right 
- box.left ) ),0 ) ;
 CONTROL_ITEM_RECT[YEAR_PART_CODE] = box ;
 CONTROL_CHAR_POS[i++].h = box.left ;
 CONTROL_CHAR_POS[i++].h = box.left + CHARACTER_OFFSET + CONTROL_FONT_WIDTH 
;

 /* Calculate hour rect and character points */
 OffsetRect( &box, ( DATE_TIME_OFFSET + ( box.right - box.left ) ),0 
) ;
 CONTROL_ITEM_RECT[HOUR_PART_CODE] = box ;
 CONTROL_CHAR_POS[i++].h = box.left ;
 CONTROL_CHAR_POS[i++].h = box.left + CHARACTER_OFFSET + CONTROL_FONT_WIDTH 
;

 /* Now calc position for colon */
 CONTROL_CHAR_POS[i++].h = box.right + CHARACTER_OFFSET ;

 /* Calculate minute rect and character points */
 OffsetRect( &box, ( CONTROL_FONT_WIDTH - 4 + 2*CHARACTER_OFFSET + ( 
box.right - box.left ) ),0 ) ;
 CONTROL_ITEM_RECT[MINUTE_PART_CODE] = box ;
 CONTROL_CHAR_POS[i++].h = box.left ;
 CONTROL_CHAR_POS[i++].h = box.left + CHARACTER_OFFSET + CONTROL_FONT_WIDTH 
;

 /* Calculate up and down buttons rects */
 OffsetRect( &box, ( DATE_TIME_OFFSET + ( box.right - box.left ) ),0 
) ;
 box.top -= 2 ;
 box.right = box.left + 11 ;
 box.bottom = box.top + 9 ;
 CONTROL_ITEM_RECT[UP_ARROW] = box ;
 OffsetRect( &box, 0, 9 ) ;
 CONTROL_ITEM_RECT[DOWN_ARROW] = box ;

 /* Zero all the update and hilite arrays out */
 for( i=0;i<NUM_PARTS;i++) {
 CONTROL_ITEM_UPDATE[i] = TRUE ;
 CONTROL_ITEM_HILITE[i] = FALSE ;
 }
 
 /* Init control hilites */
 CONTROL_HILITED = 0 ;
 CONTROL_LST_HILITED = 0 ;
 
 /* This is the number of times autoTrack is called before updating date 
*/
 DE_BOUNCER = DELAY ;

 /* Number of days in the month */
 NUM_DAYS[0] = 31 ;
 NUM_DAYS[1] = 28 ;
 NUM_DAYS[2] = 31 ;
 NUM_DAYS[3] = 30 ;
 NUM_DAYS[4] = 31 ;
 NUM_DAYS[5] = 30 ;
 NUM_DAYS[6] = 31 ;
 NUM_DAYS[7] = 31 ;
 NUM_DAYS[8] = 30 ;
 NUM_DAYS[9] = 31 ;
 NUM_DAYS[10] = 30 ;
 NUM_DAYS[11] = 31 ;
 
 /* Handle leap years */
 /* Note: year MOD 4 handles the leap year every 4 years but 
      this does not take into account the fact that every 4 
      centuries the leap year is skipped.  This will happen 
 again in the year 2000, which by our algorithm       is a leap year, 
but in acuality is not.  If this code is           still in use till 
the year 2000 I will gladly update it. */
 if( ( CONTROL_DATE_TIME.year % 4 ) == 0 ) {
 NUM_DAYS[1] = 29 ;
 }else{
 NUM_DAYS[1] = 28 ;
 }

 return ;
}
void doDrawControl( parameter, my_control )
long parameter ;
ControlHandle my_control ;
{
 BitMap arrows ;
 Rect box ;
 Rect box2 ;
 int i ;

 /* Save old clip region */
 if( OLD_CLIP != NULL && NEW_CLIP != NULL ) {
 GetClip( OLD_CLIP ) ;
 RectRgn( NEW_CLIP, &CONTROL_RECT ) ;
 SectRgn( OLD_CLIP, NEW_CLIP, NEW_CLIP ) ;
 SetClip( NEW_CLIP ) ;

 /* Set update and hilite array */
 if( parameter >= 0 && parameter < NUM_PARTS ) { 
 CONTROL_ITEM_UPDATE[parameter] = TRUE ;
 }
 if( CONTROL_HILITE > 0 && CONTROL_HILITE < UP_ARROW ) { 
 CONTROL_ITEM_HILITE[CONTROL_HILITE] = TRUE ;
 CONTROL_HILITED = CONTROL_HILITE ;
 CONTROL_LST_HILITED = CONTROL_HILITED ;
 CONTROL_ITEM_UPDATE[UP_ARROW] = TRUE ;
 }else if( CONTROL_HILITE == 0 ) {
 CONTROL_HILITED = 0 ;
 CONTROL_ITEM_UPDATE[UP_ARROW] = TRUE ;
 }else if( CONTROL_HILITE == UP_ARROW || CONTROL_HILITE == DOWN_ARROW 
) {
 CONTROL_HILITED = CONTROL_LST_HILITED ;
 CONTROL_ITEM_HILITE[CONTROL_LST_HILITED] = TRUE ;
 CONTROL_ITEM_UPDATE[CONTROL_LST_HILITED] = TRUE ;
 CONTROL_ITEM_UPDATE[UP_ARROW] = TRUE ;
 }
 for( i=0;i<NUM_PARTS;i++ ) {
 if( parameter == 0 ) CONTROL_ITEM_UPDATE[i] = TRUE ;
 if( parameter == i ) CONTROL_ITEM_UPDATE[i] = TRUE ;
 if( ( CONTROL_ITEM_HILITE[i] ) && ( i != CONTROL_HILITED )  && ( CONTROL_HILITED 
< UP_ARROW ) ) {
 CONTROL_ITEM_HILITE[i] = FALSE ;
 CONTROL_ITEM_UPDATE[i] = TRUE ;
 }
 }

 /* Now do drawing */
 for( i=0;i<NUM_PARTS;i++ ) {
 if( CONTROL_ITEM_UPDATE[i] ) {
 CONTROL_ITEM_UPDATE[i] = FALSE ;  
 switch( i ) {
 case 0:
 /* Frame the control */
 box = CONTROL_RECT ;
 if( parameter == 0 ) {
 EraseRect( &box ) ;
 }
 box.bottom -= 2 ;
 box.right -= 2 ;
 FrameRect( &box ) ;
 /* Now draw the shadow */
 MoveTo( box.left+1, box.bottom ) ;
 LineTo( box.right, box.bottom ) ;
 LineTo( box.right, box.top+1 ) ;
 /* Also draw the slashes and colon here */
 MoveTo( CONTROL_CHAR_POS[2].h,
  CONTROL_CHAR_POS[2].v ) ;
 DrawChar( CONTROL_CHAR_ARY[2] ) ;
 MoveTo( CONTROL_CHAR_POS[5].h,
  CONTROL_CHAR_POS[5].v ) ;
 DrawChar( CONTROL_CHAR_ARY[5] ) ;
 MoveTo( CONTROL_CHAR_POS[10].h,
  CONTROL_CHAR_POS[10].v ) ;
 DrawChar( CONTROL_CHAR_ARY[10] ) ;
 break ;
 case MONTH_PART_CODE:
 /* Draw month characters */
 EraseRect( &CONTROL_ITEM_RECT[MONTH_PART_CODE] ) ;
 MoveTo( CONTROL_CHAR_POS[0].h,
  CONTROL_CHAR_POS[0].v ) ;
 DrawChar( CONTROL_CHAR_ARY[0] ) ;
 MoveTo( CONTROL_CHAR_POS[1].h,
  CONTROL_CHAR_POS[1].v ) ;
 DrawChar( CONTROL_CHAR_ARY[1] ) ;
 if( CONTROL_ITEM_HILITE[MONTH_PART_CODE] ) {
 InvertRect(
  &CONTROL_ITEM_RECT[MONTH_PART_CODE] ) ;
 }
 break ;
 case DAY_PART_CODE:
 /* Draw day characters */
 EraseRect( &CONTROL_ITEM_RECT[DAY_PART_CODE] ) ;
 MoveTo( CONTROL_CHAR_POS[3].h,
  CONTROL_CHAR_POS[3].v ) ;
 DrawChar( CONTROL_CHAR_ARY[3] ) ;
 MoveTo( CONTROL_CHAR_POS[4].h,
  CONTROL_CHAR_POS[4].v ) ;
 DrawChar( CONTROL_CHAR_ARY[4] ) ;
 if( CONTROL_ITEM_HILITE[DAY_PART_CODE] ) {
 InvertRect(&CONTROL_ITEM_RECT[DAY_PART_CODE] ) ;
 }
 break ;
 case YEAR_PART_CODE:
 /* Draw year characters */
 EraseRect( &CONTROL_ITEM_RECT[YEAR_PART_CODE] ) ;
 MoveTo( CONTROL_CHAR_POS[6].h,
  CONTROL_CHAR_POS[6].v ) ;
 DrawChar( CONTROL_CHAR_ARY[6] ) ;
 MoveTo( CONTROL_CHAR_POS[7].h,
  CONTROL_CHAR_POS[7].v ) ;
 DrawChar( CONTROL_CHAR_ARY[7] ) ;
 if( CONTROL_ITEM_HILITE[YEAR_PART_CODE] ) {
 InvertRect(&CONTROL_ITEM_RECT[YEAR_PART_CODE] ) ;
 }
 break ;
 case HOUR_PART_CODE:
 /* Draw hour characters */
 EraseRect( &CONTROL_ITEM_RECT[HOUR_PART_CODE] ) ;
 MoveTo( CONTROL_CHAR_POS[8].h,
  CONTROL_CHAR_POS[8].v ) ;
 DrawChar( CONTROL_CHAR_ARY[8] ) ;
 MoveTo( CONTROL_CHAR_POS[9].h,
  CONTROL_CHAR_POS[9].v ) ;
 DrawChar( CONTROL_CHAR_ARY[9] ) ;
 if( CONTROL_ITEM_HILITE[HOUR_PART_CODE] ) {
 InvertRect(&CONTROL_ITEM_RECT[HOUR_PART_CODE] ) ;
 }
 break ;
 case MINUTE_PART_CODE:
 /* Draw minute characters */
 EraseRect( &CONTROL_ITEM_RECT[MINUTE_PART_CODE]) ;
 MoveTo( CONTROL_CHAR_POS[11].h,
  CONTROL_CHAR_POS[11].v ) ;
 DrawChar( CONTROL_CHAR_ARY[11] ) ;
 MoveTo( CONTROL_CHAR_POS[12].h,
  CONTROL_CHAR_POS[12].v ) ;
 DrawChar( CON-§_CHAR_ARY[12] ) ;
 if( CONTROL_ITEM_HILITE[MINUTE_PART_CODE] ) {
 InvertRect(&CONTROL_ITEM_RECT[MINUTE_PART_CODE]);
 }
 break ;
 case UP_ARROW:
 case DOWN_ARROW:
 /* draw the arrows */
 SetRect( &box, CONTROL_ITEM_RECT[UP_ARROW].left, 
     CONTROL_ITEM_RECT[UP_ARROW].top,
 CONTROL_ITEM_RECT[DOWN_ARROW].right, 
    CONTROL_ITEM_RECT[DOWN_ARROW].bottom ) ;
 /* If there is nothing hilited erase arrows */
 if( CONTROL_HILITED == 0 ) {
 EraseRect( &box ) ;
 }else{
 SetRect( &box2, 0,0,11,18 ) ;
 arrows.rowBytes = 2 ;
 arrows.bounds = box2 ;
 arrows.baseAddr = bits ;
 CopyBits( &arrows, &CONTROL_WINDOW->portBits, 
    &box2, &box, srcOr, NULL ) ;
 }
 break ;
 }
 }
 }
 
 /* Restore old clip region */
 SetClip( OLD_CLIP ) ;
 }
 return ;
}
long doTestControl( pt, my_control )
long pt ;
ControlHandle my_control ;
{
 int i ;
 long result = 0 ;
 
 for( i=1;i<NUM_PARTS;i++ ) {
 if( PtInRect( pt, &CONTROL_ITEM_RECT[i] ) ) {
 result = i ;
 break ;
 }
 }
 return result ;
}
void doCalcCRgns( region, my_control )
RgnHandle region ;
ControlHandle my_control ;
{
 RectRgn( (RgnHandle)region, &CONTROL_RECT ) ;
 return ;
}
void doTrackControl( hilite, my_control )
int hilite ;
ControlHandle my_control ;
{
 /* Is it in the arrows */
 if( hilite == UP_ARROW || hilite == DOWN_ARROW ) {
 /* Delay to keep from changing the numbers too fast */
 if( DE_BOUNCER ) {
 DE_BOUNCER-- ;
 return ;
 }
 if( hilite == UP_ARROW ) {
 switch( CONTROL_HILITED ) {
 case MONTH_PART_CODE:
 if( CONTROL_DATE_TIME.month >= 12 ) {
 CONTROL_DATE_TIME.month = 1 ;
 }else CONTROL_DATE_TIME.month++ ;
 CONTROL_ITEM_UPDATE[MONTH_PART_CODE] = TRUE ;
 break ;
 case DAY_PART_CODE:
 if( CONTROL_DATE_TIME.day >=
  NUM_DAYS[CONTROL_DATE_TIME.month-1] ) {
 CONTROL_DATE_TIME.day = 1 ;
 }else CONTROL_DATE_TIME.day++ ;
 CONTROL_ITEM_UPDATE[DAY_PART_CODE] = TRUE ;
 break ;
 case YEAR_PART_CODE:
 if( CONTROL_DATE_TIME.year >= 1999 ) {
 CONTROL_DATE_TIME.year = 1904 ;
 }else CONTROL_DATE_TIME.year++ ;
 CONTROL_ITEM_UPDATE[YEAR_PART_CODE] = TRUE ;
 if( ( CONTROL_DATE_TIME.year % 4 ) == 0 ) {
 NUM_DAYS[1] = 29 ;
 }else{
 NUM_DAYS[1] = 28 ;
 }
 break ;
 case HOUR_PART_CODE:
 if( CONTROL_DATE_TIME.hour >= 23 ) {
 CONTROL_DATE_TIME.hour = 0 ;
 }else CONTROL_DATE_TIME.hour++ ;
 CONTROL_ITEM_UPDATE[HOUR_PART_CODE] = TRUE ;
 break ;
 case MINUTE_PART_CODE:
 if( CONTROL_DATE_TIME.minute >= 59 ) {
 CONTROL_DATE_TIME.minute = 0 ;
 }else CONTROL_DATE_TIME.minute++ ;
 CONTROL_ITEM_UPDATE[MINUTE_PART_CODE] = TRUE ;
 break ;
 }
 }else if( hilite == DOWN_ARROW ) {
 switch( CONTROL_HILITED ) {
 case MONTH_PART_CODE:
 if( CONTROL_DATE_TIME.month <= 1 ) {
 CONTROL_DATE_TIME.month = 12 ;
 }else CONTROL_DATE_TIME.month-- ;
 CONTROL_ITEM_UPDATE[MONTH_PART_CODE] = TRUE ;
 break ;
 case DAY_PART_CODE:
 if( CONTROL_DATE_TIME.day <= 1 ) {
 CONTROL_DATE_TIME.day =
  NUM_DAYS[CONTROL_DATE_TIME.month-1] ;
 }else CONTROL_DATE_TIME.day-- ;
 CONTROL_ITEM_UPDATE[DAY_PART_CODE] = TRUE ;
 break ;
 case YEAR_PART_CODE:
 if( CONTROL_DATE_TIME.year <= 1904 ) {
 CONTROL_DATE_TIME.year = 1999 ;
 }else CONTROL_DATE_TIME.year-- ;
 CONTROL_ITEM_UPDATE[YEAR_PART_CODE] = TRUE ;
 if( ( CONTROL_DATE_TIME.year % 4 ) == 0 ) {
 NUM_DAYS[1] = 29 ;
 }else{
 NUM_DAYS[1] = 28 ;
 }
 break ;
 case HOUR_PART_CODE:
 if( CONTROL_DATE_TIME.hour <= 0 ) {
 CONTROL_DATE_TIME.hour = 23 ;
 }else CONTROL_DATE_TIME.hour-- ;
 CONTROL_ITEM_UPDATE[HOUR_PART_CODE] = TRUE ;
 break ;
 case MINUTE_PART_CODE:
 if( CONTROL_DATE_TIME.minute <= 0 ) {
 CONTROL_DATE_TIME.minute = 59 ;
 }else CONTROL_DATE_TIME.minute-- ;
 CONTROL_ITEM_UPDATE[MINUTE_PART_CODE] = TRUE ;
 break ;
 }
 }
 /* Reset delay */
 DE_BOUNCER = DELAY ;
 NEW_DATE_TIME = CONTROL_DATE_TIME ;
 Date2Chars( &CONTROL_DATE_TIME, CONTROL_CHAR_ARY ) ;
 doDrawControl( hilite, my_control ) ;
 }else if( hilite >= 0 && hilite < UP_ARROW ) {
 HiliteControl( my_control, hilite ) ;
 }
 return ;
}
Listing: date_convert.c

#include <OSUtil.h>

void Date2Chars( DateTimeRec *, int * ) ;

void Date2Chars( date_ptr, char_array )
DateTimeRec *date_ptr ;
int char_array[ ] ;
{
 int i = 0 ;
 Str255 str ;
 long number ;
 
 /* convert month */
 number = date_ptr->month ;
 NumToString( number, str ) ;
 if( number > 9 ) {
 char_array[i++] = str[1] ;
 char_array[i++] = str[2] ;
 }else{
 char_array[i++] = ‘0’ ;
 char_array[i++] = str[1] ;
 }

 /* Add in slash */
 char_array[i++] = ‘/’ ;

 /* convert day */
 number = date_ptr->day ;
 NumToString( number, str ) ;
 if( number > 9 ) {
 char_array[i++] = str[1] ;
 char_array[i++] = str[2] ;
 }else{
 char_array[i++] = ‘0’ ;
 char_array[i++] = str[1] ;
 }

 /* Add in slash */
 char_array[i++] = ‘/’ ;

 /* convert year */
 number = date_ptr->year ;
 NumToString( number, str ) ;
 char_array[i++] = str[3] ;
 char_array[i++] = str[4] ;
 
 /* convert hour */
 number = date_ptr->hour ;
 NumToString( number, str ) ;
 if( number > 9 ) {
 char_array[i++] = str[1] ;
 char_array[i++] = str[2] ;
 }else{
 char_array[i++] = ‘0’ ;
 char_array[i++] = str[1] ;
 }
 
 /* Add in colon */
 char_array[i++] = ‘:’ ;

 /* convert minute */
 number = date_ptr->minute ;
 NumToString( number, str ) ;
 if( number > 9 ) {
 char_array[i++] = str[1] ;
 char_array[i++] = str[2] ;
 }else{
 char_array[i++] = ‘0’ ;
 char_array[i++] = str[1] ;
 }
 
 return ;
}
Listing test_cdef_main.c
/******** System includes ********/
#include <Quickdraw.h>
#include <ControlMgr.h>
#include <MemoryMgr.h>
#include <OSUtil.h>
#include <WindowMgr.h>
#include <EventMgr.h>
/**********************************/

/******** defines ********/
#define NULL0L
/**********************************/

/******** prototypes ********/
void main( void ) ;
void TestControl( void ) ;
/**********************************/

/******** globals ********/
Rect test_window_rect = { 40, 10, 300, 400 } ;
Rect test_control_rect = { 10, 10, 34, 150 } ;
WindowPtr window_ptr ;
ControlHandle control_hdl ;
ControlHandle control_hdl2 ;
long tmp ;
EventRecord event ;
Point pt ;
int part_code ;
int last_part_code ;
ControlHandle which_control ;
RgnHandle clip ;
Rect rect ;
/**********************************/

void main( )
{
 /* Initialize the macintosh managers */
 InitGraf( ( Ptr) &thePort ) ;
 InitFonts( ) ;
 InitWindows( ) ;
 InitCursor( ) ;
 InitMenus( ) ;
 TEInit( ) ;
 InitDialogs( 0L ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 FlushEvents( everyEvent, 0 ) ;

 /* Now call test control routine */
 TestControl( ) ;
 
 return ;
}
void TestControl( )
{
 rect.top = 0 ;
 rect.left = 0 ;
 rect.right = 512 ;
 rect.bottom = 382 ;
 
 /* Open the window */
 window_ptr = NewWindow( NULL, &test_window_rect, “\ptest window”, TRUE, 
1, (WindowPtr)-1L, FALSE, 0L ) ;
 
 if( window_ptr == NULL ) return ;
 
 SetPort( window_ptr ) ;
 /* Open the control */
 control_hdl = NewControl( window_ptr, &test_control_rect, “\ptest control”, 
TRUE, 0, 0, 0, 32, 0L ) ;
 OffsetRect( &test_control_rect, 150, 50 ) ;
 control_hdl2 = NewControl( window_ptr, &test_control_rect, “\ptest control”, 
TRUE, 0, 0, 0, 32, 0L ) ;
 
 MoveTo( 110, 250 ) ;
 DrawString( “\pHit any key to quit” ) ;
 /* Now start miniature event loop */
 while( TRUE ) {
 GetNextEvent( everyEvent, &event ) ;
 pt = event.where ;
 SetPort( window_ptr ) ;
 GlobalToLocal( &pt ) ;
 
 if( event.what == mouseDown ) {
 part_code=FindControl( pt, window_ptr, &which_control) ;
 
 if( which_control == NULL ) {
 if( (**control_hdl).contrlHilite != 0 ) {
 HiliteControl( control_hdl, 0 ) ;
 }
 if( (**control_hdl2).contrlHilite != 0 ) {
 HiliteControl( control_hdl2, 0 ) ;
 }
 SysBeep( 5 ) ;
 }else{
 part_code = TrackControl( which_control, pt, 
             (ProcPtr)-1L ) ;
 HiliteControl( which_control, part_code ) ;
 if( which_control == control_hdl ) {
 if( (**control_hdl2).contrlHilite != 0 ) {
 HiliteControl( control_hdl2, 0 ) ;
 }
 }
 if( which_control == control_hdl2 ) {
 if( (**control_hdl).contrlHilite != 0 ) {
 HiliteControl( control_hdl, 0 ) ;
 }
 }
 }
 }
 if( event.what == keyDown ) {
 break ;
 }
 }
   
 /* Close the control */
 DisposeControl( control_hdl ) ;
 DisposeControl( control_hdl2 ) ;

 /* Close the window */
 DisposeWindow( window_ptr ) ;
 return ;
}
Listing: debug_test_cdef.main.c
/******** System includes ********/
#include <Quickdraw.h>
#include <ControlMgr.h>
#include <MemoryMgr.h>
#include <OSUtil.h>
#include <WindowMgr.h>
#include <EventMgr.h>
/**********************************/
/******** typedefs ********/
typedef struct {
 char *cdef_ptr ;
} CJMP, *CJMP_PTR, **CJMP_HDL ;
/**********************************/

/******** defines ********/
#define NULL0L
/**********************************/

/******** prototypes ********/
extern pascal long _main( ) ;
void main( void ) ;
void TestControl( void ) ;
/**********************************/
/******** globals ********/
CJMP_HDL cjmp_hdl ;
Rect test_window_rect = { 40, 10, 300, 400 } ;
Rect test_control_rect = { 10, 10, 34, 150 } ;
/**********************************/

void main( )
{
 /* Initialize the macintosh managers */
 InitGraf( ( Ptr) &thePort ) ;
 InitFonts( ) ;
 InitWindows( ) ;
 InitCursor( ) ;
 InitMenus( ) ;
 TEInit( ) ;
 InitDialogs( 0L ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 MoreMasters( ) ;
 FlushEvents( everyEvent, 0 ) ;

 if( ( cjmp_hdl = (CJMP_HDL)GetResource( ‘CJMP’, 9999 ) )  == 0L ) {
 /* First create CJMP structure */
 cjmp_hdl = (CJMP_HDL)NewHandle( sizeof( CJMP ) ) ;
 
 /* Now make it into a resource so that the dummy cdef can access it 
*/
 AddResource( cjmp_hdl, ‘CJMP’, 9999, “\pcdef jump structure” ) ;
 }
 /* Now install pointer to real cdef */
 (**cjmp_hdl).cdef_ptr = (char *)_main ;
 
 /* Now call test control routine */
 TestControl( ) ;
 
 /* Now remove the resource */
 RmveResource( cjmp_hdl ) ;
 
 return ;
}
void TestControl( )
{
 WindowPtr window_ptr ;
 ControlHandle control_hdl ;
 ControlHandle control_hdl2 ;
 long tmp ;
 EventRecord event ;
 Point pt ;
 int part_code ;
 int last_part_code ;
 ControlHandle which_control ;
 
 /* Open the window */
 window_ptr = NewWindow( NULL, &test_window_rect, “\ptest window”, TRUE, 
1, (WindowPtr)-1L, FALSE, 0L ) ;
 
 if( window_ptr == NULL ) return ;
 
 SetPort( window_ptr ) ;
 /* Open the control */
 control_hdl = NewControl( window_ptr, &test_control_rect, “\ptest control”,
   TRUE, 0, 0, 0, 32, 0L ) ;
 OffsetRect( &test_control_rect, 150, 50 ) ;
 control_hdl2 = NewControl( window_ptr, &test_control_rect, “\ptest control”, 
TRUE, 0, 0, 0, 32, 0L ) ;
 
 /* Now start miniature event loop */
 while( TRUE ) {
 GetNextEvent( everyEvent, &event ) ;
 pt = event.where ;
 SetPort( window_ptr ) ;
 GlobalToLocal( &pt ) ;
 
 if( event.what == mouseDown ) {
 part_code = FindControl(pt, window_ptr, &which_control);
 
 if( which_control == NULL ) {
 if( (**control_hdl).contrlHilite != 0 ) {
 HiliteControl( control_hdl, 0 ) ;
 }
 if( (**control_hdl2).contrlHilite != 0 ) {
 HiliteControl( control_hdl2, 0 ) ;
 }
 SysBeep( 5 ) ;
 }else{
 part_code = TrackControl( which_control, pt, 
                                           (ProcPtr)-1L ) ;
 HiliteControl( which_control, part_code ) ;
 if( which_control == control_hdl ) {
 if( (**control_hdl2).contrlHilite != 0 ) {
 HiliteControl( control_hdl2, 0 ) ;
 }
 }
 if( which_control == control_hdl2 ) {
 if( (**control_hdl).contrlHilite != 0 ) {
 HiliteControl( control_hdl, 0 ) ;
 }
 }
 }
 }
 if( event.what == keyDown ) {
 break ;
 }
 }
 /* Close the control */
 DisposeControl( control_hdl ) ;
 DisposeControl( control_hdl2 ) ;
 /* Close the window */
 DisposeWindow( window_ptr ) ;
 return ;
}
Listing:  dummy_cdef.c
/******** System includes ********/
#include <ResourceMgr.h>
#include <ControlMgr.h>
#include <MemoryMgr.h>
/**********************************/
/******** typedefs ********/
typedef struct {
 char *cdef_ptr ;
} CJMP, *CJMP_PTR, **CJMP_HDL ;
/**********************************/
/******** Subroutine prototypes ********/
pascal long main( int, ControlHandle, int, long ) ;
/**********************************/

pascal long main( varCode, theControl, message, param )
int varCode ;
ControlHandle theControl ;
int message ;
long param ;
{
 long result ;
 CJMP_HDL cjmp_hdl ;
 
 /* First get the CJMP resource */
 cjmp_hdl = (CJMP_HDL)GetResource( ‘CJMP’, 9999 ) ;
 if( cjmp_hdl != 0L ) {
 /* Now call the real cdef routine */
 result = CallPascalL( varCode, theControl, message, param,    
   (**cjmp_hdl).cdef_ptr ) ;
 }
 return result ;
}

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

TextSoap 8.4.1 - Automate tedious text d...
TextSoap can automatically remove unwanted characters, fix up messed up carriage returns, and do pretty much anything else that we can think of to text. Save time and effort. Be more productive. Stop... Read more
Backblaze 4.3.0.44 - Online backup servi...
Backblaze is an online backup service designed from the ground-up for the Mac. With unlimited storage available for $5 per month, as well as a free 15-day trial, peace of mind is within reach with... Read more
Numi 3.15 - Menu-bar calculator supports...
Numi is a calculator that magically combines calculations with text, and allows you to freely share your computations. Numi combines text editor and calculator Support plain English. For example, '5... Read more
EtreCheck 3.3.3 - For troubleshooting yo...
EtreCheck is an app that displays the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support Communities to... Read more
BusyContacts 1.1.8 - Fast, efficient con...
BusyContacts is a contact manager for OS X that makes creating, finding, and managing contacts faster and more efficient. It brings to contact management the same power, flexibility, and sharing... Read more
TunnelBear 3.0.14 - Subscription-based p...
TunnelBear is a subscription-based virtual private network (VPN) service and companion app, enabling you to browse the internet privately and securely. Features Browse privately - Secure your data... Read more
Apple Final Cut Pro X 10.3.4 - Professio...
Apple Final Cut Pro X is a professional video editing solution.Completely redesigned from the ground up, Final Cut Pro adds extraordinary speed, quality, and flexibility to every part of the post-... Read more
Hopper Disassembler 4.2.1- - Binary disa...
Hopper Disassembler is a binary disassembler, decompiler, and debugger for 32-bit and 64-bit executables. It will let you disassemble any binary you want, and provide you all the information about... Read more
Slack 2.6.2 - Collaborative communicatio...
Slack is a collaborative communication app that simplifies real-time messaging, archiving, and search for modern working teams. Version 2.6.2: Fixed Inexplicably, context menus and spell-check... Read more
Arq 5.8.5 - Online backup to Google Driv...
Arq is super-easy online backup for Mac and Windows computers. Back up to your own cloud account (Amazon Cloud Drive, Google Drive, Dropbox, OneDrive, Google Cloud Storage, any S3-compatible server... Read more

Latest Forum Discussions

See All

The best new games we played this week
We were quite busy this week. A bunch of big mobile games launched over the past few days, alongside a few teeny surprises. There're lots of quality games to load your phone with. We've gone and picked out five of our favorites for the week. [... | Read more »
Magikarp Jump beginner's guide
Magikarp Jump is a mystifying little game. Part Tamagotchi, part idle clicker, there's not a whole lot of video game there, per se, but for some reason we can't help coming back to it again and again. Your goal is to train up a little Magikarp to... | Read more »
Goat Simulator PAYDAY (Games)
Goat Simulator PAYDAY 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: ** IMPORTANT - SUPPORTED DEVICES **iPhone 4S, iPad 2, iPod Touch 5 or better Goat Simulator: Payday is the most... | Read more »
GRID Autosport delayed until autumn
Sorry mobile racing fans -- GRID Autosport has been delayed a few months. The game is now expected to launch this fall on iOS. Feral Interactive announced that they wanted more time to work on the game's UI and overall performance before launching... | Read more »
Zombie Gunship Survival Beginner's...
The much anticipated Zombie Gunship Survival is here. In this latest entry in the Zombie Gunship franchise, you're tasked with supporting ground troops and protecting your base from the zombie horde. There's a lot of rich base building fun, and... | Read more »
Mordheim: Warband Skirmish (Games)
Mordheim: Warband Skirmish 1.2.2 Device: iOS Universal Category: Games Price: $3.99, Version: 1.2.2 (iTunes) Description: Explore the ruins of the City of Mordheim, clash with other scavenging warbands and collect Wyrdstone -... | Read more »
Mordheim: Warband Skirmish brings tablet...
Legendary Games has just launched Mordheim: Warband Skirmish, a new turn-based action game for iOS and Android. | Read more »
Magikarp Jump splashes onto Android worl...
If you're tired ofPokémon GObut still want something to satisfy your mobilePokémon fix,Magikarp Jumpmay just do the trick. It's out now on Android devices the world over. While it looks like a simple arcade jumper, there's quite a bit more to it... | Read more »
Purrfectly charming open-world RPG Cat Q...
Cat Quest, an expansive open-world RPG from former Koei-Tecmo developers, got a new gameplay trailer today. The video showcases the combat and exploration features of this feline-themed RPG. Cat puns abound as you travel across a large map in a... | Read more »
Jaipur: A Card Game of Duels (Games)
Jaipur: A Card Game of Duels 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: ** WARNING: iPad 2, iPad Mini 1 & iPhone 4S are NOT compatible. ** *** Special Launch Price for a limited... | Read more »

Price Scanner via MacPrices.net

Memorial Day savings: 13-inch Touch Bar MacBo...
B&H Photo has the 2016 Apple 13″ Touch Bar MacBook Pros in stock today and on sale for up to $150 off MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: - 13″ 2.9GHz/512GB... Read more
Apple refurbished 13-inch MacBook Airs availa...
Apple has Certified Refurbished 2016 13″ MacBook Airs available starting at $849. An Apple one-year warranty is included with each MacBook, and shipping is free: - 13″ 1.6GHz/8GB/128GB MacBook Air: $... Read more
Apple restocks refurbished 11-inch MacBook Ai...
Apple has Certified Refurbished 11″ MacBook Airs (the latest models recently discontinued by Apple), available for up to $170 off original MSRP. An Apple one-year warranty is included with each... Read more
12-inch 1.2GHz Retina MacBooks on sale for up...
B&H has 12″ 1.2GHz Retina MacBooks on sale for up to $150 off MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: - 12″ 1.2GHz Space Gray Retina MacBook: $1449.99 $150 off... Read more
15-inch 2.7GHz Silver Touch Bar MacBook Pro o...
MacMall has the 15-inch 2.7GHz Silver Touch Bar MacBook Pro (MLW82LL/A) on sale for $2569 as part of their Memorial Day sale. Shipping is free. Their price is $230 off MSRP. Read more
Free Tread Wisely Mobile App Endorsed By Fath...
Just in time for the summer driving season, Cooper Tire & Rubber Company has announced the launch of a new Tread Wisely mobile app. Designed to promote tire and vehicle safety among teens and... Read more
Commercial Notebooks And Detachable Tablets W...
Worldwide shipments of personal computing devices (PCDs), comprised of traditional PCs (a combination of desktop, notebook, and workstations) and tablets (slates and detachables), are forecast to... Read more
Best value this Memorial Day weekend: Touch B...
Apple has Certified Refurbished 2016 15″ and 13″ MacBook Pros available for $230 to $420 off original MSRP. An Apple one-year warranty is included with each model, and shipping is free: - 15″ 2.6GHz... Read more
13-inch MacBook Airs on sale for up to $130 o...
Overstock.com has 13″ MacBook Airs on sale for up to $130 off MSRP including free shipping: - 13″ 1.6GHz/128GB MacBook Air (sku MMGF2LL/A): $869.99 $130 off MSRP - 13″ 1.6GHz/256GB MacBook Air (sku... Read more
2.8GHz Mac mini available for $973 with free...
Adorama has the 2.8GHz Mac mini available for $973, $16 off MSRP, including a free copy of Apple’s 3-Year AppleCare Protection Plan. Shipping is free, and Adorama charges sales tax in NY & NJ... Read more

Jobs Board

*Apple* Media Products - Commerce Engineerin...
Apple Media Products - Commerce Engineering Manager Job Number: 57037480 Santa Clara Valley, California, United States Posted: Apr. 18, 2017 Weekly Hours: 40.00 Job Read more
Best Buy *Apple* Computing Master - Best Bu...
**509643BR** **Job Title:** Best Buy Apple Computing Master **Location Number:** 001482- Apple Valley-Store **Job Description:** **What does a Best Buy Apple Read more
*Apple* Media Products - Commerce Engineerin...
Apple Media Products - Commerce Engineering Manager Job Number: 57037480 Santa Clara Valley, California, United States Posted: Apr. 18, 2017 Weekly Hours: 40.00 Job Read more
*Apple* Mac and Mobility Engineer - Infogrou...
Title: Apple Mac and Mobility Engineer Location: Portland, OR Area Type: 12 month contract Job: 17412 Here's a chance to take your skills to the limit, learn new Read more
*Apple* Retail - Multiple Positions, White P...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.