TweetFollow Us on Twitter

Text Window
Volume Number:1
Issue Number:6
Column Tag:C WORKSHOP

Windows for Text Editing

By Robert B. Denny

Windows for Text Editing

One of the most comon uses of windows in Macintosh applications is for manipulation of text. The user interface for text editing is one of the cornerstones of Mac technology.

This month’s C Workshop deals with implementing editing windows. We’ll bring together much of what was presented in previous columns, and add new informa- tion on TextEdit’s services. We’ll also show some specifics on using the Control Manager to handle scroll bars, and their use in scrolling our view of text managed by TextEdit.

One rather important issue that will not be covered is file I/O. It’s important to realize that TextEdit manages opera- tions on text in memory. If you want to work with text in a file, you must provide the services for getting text into and out of memory in manageable chunks for TextEdit to work with.

TextEdit Power

TextEdit is one of the most powerful of Macintosh’s system service packages. The Mac designers realized that editing text is probably the most pervasive user operation of all, and that standardizing the editing interface would make the Mac easy to use. Therefore, they have pro- vided us with a remarkably flexible and user-friendly editing package.

TextEdit consists of a set of system services for displaying and manipulating text. Text is stored in coded form in a linear array hooked to a master data structure called a TERec. The TERec is to TextEdit as the WindowRecord is to the Window Manager.

The display services of TextEdit handle drawing of text in the window, line breaking with optional word wrap, blink- ing the caret and showing selected ranges of text. The manipulating services handle text selection, insertion, deletion, and the scrap services of copy, cut and paste, operating on the actual text stored in memory and on the clipboard. It is a good idea to keep the concepts of display and manipulation separate in your mind.

TextEdit is reasonably documented in Inside Macintosh. It can be difficult to keep an overall perspective on things, though, when an editing window involves so many of Macintosh’s services and their data structures. Figure 1 shows a bird’s eye view of most of the data structures involved in an editing window.

Using TextEdit: Statics

There are three main things to get set up in preparation for using TextEdit with a window. First, you must create a TERec with a filled-in handle to the array where the text will be stored. Next, you must define two very important rectangles, the ViewRect and the DestRect. First, let’s look at the TERec. As usual, its structure will tell us some important things about TextEdit. The names of the structure members have been taken directly from the Lisa Pascal interface to TextEdit in the file TOOLINTF.TEXT.

The meaning of most of the fields is shown in IM. We’ll document some of the others, though you won’t normally use them. “selPoint” is the mouseLoc of the current selection point. “active” is a boolean telling whether the related window is active. This is used to control caret blinking and highlighting of selected text during window updates. “wordBreak” is a pointer to the routine that calculates word breaks (this has interesting possi- bilities). “clickLoop” is a pointer to the routine called when the mouse is clicked in text. It handles tracking the mouse and highlighting the selected text on the fly while the mouse is pressed. “clickTime” and “clickLoc” mark the place and time where & when the mouse was first clicked. Presumably, they are the property of the clickLoop routine. “recalBack” is a boolean that controls whether line breaks will be continuously recalculated in background or not and “recalLines” is a boolean that indicates whether a recalculation is under way. Finally, “caretState” indicates whether the caret is on or not, and “caretTime” contains the time for the next caret blink.

struct TERec
 {
 Rect destRect;
 Rect viewRect;
 Rect selRect;
 short  lineHeight;   
 short  firstBL;
 Point  selPoint;
 short  selStart;
 short  selEnd;
 short  active;
 long wordBreak;
 long clikLoop;
 long clickTime;
 short  clickLoc;
 long caretTime;
 short  caretState;
 short  just;
 short  TElength;
 Handle hText;
 short  recalBack;
 short  recalLines;
 short  clikStuff;
 short  crOnly;
 short  txFont;
 Style  txFace;
 short  txMode;
 short  txSize;
 GrafPtrinPort;
 Ptr  highHook;
 Ptr  caretHook;
 short  nLines;
 short  lineStarts[1];
 };

Before doing anything, your application must call TEInit(). This allocates a single common scrap area for use by TextEdit.

To allocate a TERec and a text array for a given window, call SetPort() for that window, then call TENew(), which returns a handle to the TERec. TENew() doesn’t take a windowPtr or a grafPtr, rather, it works on the current port, hence the need to call SetPort() before TENew().

The two parameters to TENew are the destRect and the viewRect. These two rectangles determine the line width and displayed portion of text. Remember the text is stored in a linear array hooked to the TERec. Refer again to Fig. 1. Notice that the TERec contains a set of pointers (actually offsets) to the places in the text where line breaks occur. How are these calculated?

Figure 2 above shows the relationship between the two rectangles. You can look at the destRect as the dimensions of the “chalkboard” where the text is to be displayed. TextEdit automatically mea- sures the length of the text in the storage array (given its font parameters) and calculates the location of the line breaks, normally employing word breaks instead of character breaks. The destRect is specified in the coordinate system of the owning window’s grafPort. Don’t forget this, it has important implications. In Figure 2, the top left corner of the destRect has negative v & h coordinate values.

The viewRect specifies the portion of the text that is actually visible. It is sort of a “clip” rectangle for the text display. Why the distinction? Consider the case of displaying text as it would print on 8-inch wide paper. The destRect would have a width of 576 pixels (72 x 8). This sets the line breaks for the paper in use.

But the window itself can be resized and scrolled around on the 8-inch wide “chalkboard”. The viewRect is used to tell TextEdit the dimensions and location in the grafPort of the “view-port” to the text display being constructed on the chalk- board.

Normally, the viewRect is set to completely enclose the content region of the window, less the scroll bar and size box areas. It too is specified in grafPort coordinates.

One final word about setting up a window for text editing. It’s a good idea to provide a 3 or 4 pixel “bleed” on the top and left of the page image. There are two schools of thought on this. One says that the bleed should be present regardless of the location of the viewRect in the destRect. The other (to which I sub- scribe says that the bleed should be present only if the destRect is at the left and/or top of the window port. The latter makes it visually easy to tell whether there is text to the left and above the viewRect by showing fragments of letters at the window’s edge.

Using TextEdit: Dynamics

Once you have set up a window for editing, you can start manipulating and displaying text. Keep in mind the following facts about TextEdit:

1. It works only on memory images of text. No file I/O is provided.

2. It does not support multiple of character fonts, styles or sizes in a single environment.

The simplest operation is insertion of text. This can be done one character at a time with TEKey() and en masse with TEinsert(). It is most common to use TEKey() in response to a keypress event. TextEdit sticks the new text into the linear array, recalculates the downstream line breaks, then posts an update event for the window, if needed.

Simple deletion is also easy. To delete the character to the left of the current insertion point or to delete the current selection, call TEKey() with the “backspace” key code. To delete the current selection (if any), call TEDelete(). TextEdit removes the deleted text from the linear array, closing up the space, recalculates the the downstream line breaks, then posts an update event for the window, if needed.

Mass operations of cut, copy and paste are hardly more difficult. Normally, you should provide both menu options and “menu keys” to trigger these operations, in accordance with the Macintosh interface guidelines. Call TECut(), TECopy() or TEPaste() to perform the operation. If there is no text currently selected, these functions are no-ops. Otherwise, the indicated opera- tion is performed, including transfers to or from the scrap allocated by TEInit(), and the already described manipulations of the linear text array and display.

How do we select text with the mouse? Recall that the TERec contains a pointer to the “clickLoop” routine, the routine responsible for tracking the mouse while it is kept pressed and highlighting selected text on the fly as the mouse is moved. How does this process get started? By calling TEClick().

So whenever your application detects a mouse press inside the viewRect of an editing window, it should call TEClick(). You can determine whether the mouse was pressed in the viewRect by calling the QuickDraw ptInRect() service with the clicked mouse location and the viewRect. If it returns TRUE, then call TEClick(). The “clickLoop” routine is entered and continues to execute until the mouse is released, at which time control is returned to the statement following the call to TEClick().

To implement the “shift-click” method of extended selection, you must determine whether the shift key was pressed at the time the mouse was clicked and pass TRUE for the “ext” parameter to the TEClick() call. For more informa- tion, see IM.

To scroll the text display in the viewRect, simply call TEScroll(). This function takes as parameters the distance (in pixels) to scroll horizontally and vertically. A zero means no scrolling in that direction.

Now let’s test your understanding of TextEdit’s coordinate system. The first person write in with the correct answer to the following question will receive a free copy of the MacTutor “source disk”:

QUESTION:

Suppose there was no TEScroll() function. How would you scroll the displayed text? Provide a C language implementation of TEScroll():

 tescroll(dh, dv, th)
   short int dh; /* Horiz amount */
   short int dv; /* Vert amount */
   TEHandle th;  /* Handle to TERec */
 {
 (.. your code ..)
 }

You must answer the question completely, i.e., furnish a complete implementation of TEScroll(), given the parameters dh and dv whose sense of positive are text motion of right and down, respectively.

There are several other TextEdit routines which can be used to perform special (unusual) operations. Also, you can make changes to some of the TERec’s fields yourself. In either case, take care to call TEUpdate() to force display changes, and/or TECalText() to force recalculation of line breaks as required.

Using Scroll Bars

Windows used for text editing generally have at least one scroll bar present (the vertical scroller). A scroll bar is a Macintosh “control”, supported by the services provided by the Control Manager. A general discussion of the control manager is beyond the scope of this article. We’ll restrict coverage to that necessary to use scroll bars. Actually, the scroll bar is the most complex of the “standard” controls, so once you understand it, you’ll have no trouble going back to understand the other controls.

Each scroll bar has associated with it a ControlRecord, which is a data structure containing the information needed by the Control manager to handle the control. Most importantly, each control has a value at a given instant. The whole purpose of a control is to visually manipulate the value of the control. Keep this in mind at all times!

Refer to Figure 1. Note that the ControlRecords for the vertical and horizontal scrollers are linked (by handles) off the WindowRecord. Also, they contain back pointers to the Window Record.

The appearance and structural makeup of a particular kind of control is determined by a “defProc”, a control definition procedure. We discussed defProcs last month in reference to windows. When you create a control, its “flavor” is determined by the defProc. The control manager is a collection of general-purpose routines; the specifics are handled by calling the defProc.

Scroll bars are handled by a defProc named “scrollBarProc”. This defProc is fairly smart. For example, when creat- ing a scroller, you pass the location and dimensions (in window local coordinates) of the enclosing rectangle. The defProc is smart enough to look at the dimensions and automatically determine if the scroller is to be a horizontal or vertical flavor (I’ve never tried to pass a square rect).

The defProc for the “document window” (documentProc) assumes that the scrollers will occupy 16-pixel strips along the right and bottom edges, with a one-pixel overlap of the window’s border. The grow image assumes this, and the size and location given to the size box assumes this. The scrollers are in the window’s content region. We detailed this in a previous edition of MacTutor.

When you detect a mouseDown event in the content region of a document window, call findControl(). If the click was in a control, the handle to the control is returned along with a “part code” indicat- ing what part of the control the mouse was clicked in. These part codes are shown symbolically in Figure 3. We’ll deal with actions to be performed later.

A frequently misunderstood area involves the display states that scrollers can take. When an edit window is inactive, the scrollers are invisible; only the scroller outlines drawn by the window’s defProc show. There are three visible states, however, as shown in Figure 4.

You’ll probably never have occasion to highlight parts of a scroller yourself. However, you may want to make the scroller “inactive” if there is nothing beyond the limits of the viewRect, if there is no reason to scroll. To make the scroller look inactive, call the highlighting function HiLiteControl() with a “part code” of 254 or 255. Using 254 leaves the scroller sensitive to mouse presses & calling FindControl(), 255 will not.

Putting It Together: Creating a Document Window

Here is some C code for creating a document window. It assumes that there is a window template resource, just for simplicity here. You can substitute NewWindow() for GetNewWindow():

/*
 * EDIT_WINDOW() - Create an “edit window”
 *
 * Inputs:
 * dest:-> destination rect
 *
 * Outputs:
 * Fills in vs_handle and hs_handle
 * with scroller handles.
 * Fills in te_handle with handle to 
 * TERec.
 * Returns the WindowPtr
 *
 * WARNING: Untested extract.
 */
WindowPtr edit_window(dest)
Rect *dest;
 {
 Rect view_rect; 
 Rect bounds_rect;
 Rect dest_rect;
 Rect drag_rect;
 Rect grow_rect;
 Rect *pr;
 WindowPtr wp;

 /*
  * Create window record on heap from
  * resource ID = “WINDOW_ID”. We use
  * some vanilla values for the window
  * drag and grow rects.
  */
 wp = GetNewWindow(WINDOW_ID,0,-1);
 SetWTitle(wp,”\013Edit Window”);
 SetRect(&drag_rect,4,24,508,338);
 SetRect(&grow_rect,100,60,512,302);
 SetPort(wp);

 /*
  * Set up TextEdit rects.  Make the
  * destRect fixed here for example.
  * Co-locate the viewRect’s top right
  * corner with the destRect’s for 4
  * pixel bleed. Leave room for scrollers
  */
 pr = &(wp->portRect);
 destRect.top = destRect.left = 4;
 destRect.bottom = 1000;
 destRect.right = 500;
 viewRect.top = destRect.top;
 viewRect.left = destRect.left;
 viewRect.bottom = pr->bottom - 15;
 viewRect.right = pr->bottom - 15;

 /*
  * Now create the TERec & text area
  */
 te_handle = TENew(&dest_rect,     &view_rect);

 /*
  * Calculate the vertical scroller rect
  * and add the scroller to the window.
  */
 bounds_rect.top = pr->top - 1;
 bounds_rect.left = pr->right - 15;
 bounds_rect.bottom = pr->bottom - 14;
 bounds_rect.right = pr->right + 1;
 vs_handle = NewControl(dwp->wp,   &bounds_rect,               “”, TRUE,
 dest_rect.top,  dest_rect.top, dest_rect.bottom,
 scrollBarProc, 1);
 ValidRect(&bounds_rect);

 /*
  * Same for the horizontal scroller
  */
 bounds_rect.top = pr->bottom - 15;
 bounds_rect.left = pr->left - 1;
 bounds_rect.bottom = pr->bottom + 1;
 bounds_rect.right = pr->right - 14;
   hs_handle = NewControl(dwp->wp, &bounds_rect,               “”, TRUE, 
dest_rect.left,
 dest_rect.left, dest_rect.right   scrollBarProc, 1);
 ValidRect(&bounds_rect);

 /*
  * Finally, draw in the “grow icon” & 
  * return the window pointer
  */
 DrawGrowIcon(wp);
 return(wp);
 }

There are some fine points to be aware of here. The scrollers are created with bounds rectangles which are calculated from the window’s portRect. The viewRect for TextEdit is also calculated from the window’s portRect. This means that the window template resource can be any reasonable size and this routine will still work.

NewControl() not only initializes the ControlRecord, it also draws the control (set to its initial value). The calls to ValidRect() prevent unnecessary drawing in response to an update event. The call to SetWTitle() passes a “Pascal” (counted) string generated the quick way.

Finally, note that the scrollers are initialized with values drawn from the TextEdit destRect. More about this later.

Event Handling: MouseDown

If your application detects a mouse- down event in the content region of a document window, it must determine if the click was in the viewRect, one of the scrollers, the grow region or a “bleed” area. I suggest you call PtInRect() first, with the viewRect. If it returns something other than FALSE (0), then the click was in a TextEdit-controlled region. If not, call FindControl(). If it returns some- thing other than NULL (0), it was in a control. If not, the click was in a bleed area and can be ignored. Here is some C code for handling a content-area click.

/*
 * content_click()
 *
 * Event record “event” is global. Shift
 * click selection not supported.
 *
 * WARNING: Untested extract.
 */
content_click()
 {
 ControlHandle ch;
 unsigned short part;
 int in_text;
 /*
  * Declare assembler action
  * routines for TrackControl().
  */
 int scroll_up();
 int scroll_down();

 /*
  * Convert event loc to current grafPort
  * local coordinates & test if in text.
  */
 GlobalToLocal(&Event.where);
 in_text = PtInRect(&event.Where,
 &((*(te_handle))->viewRect));

 /*
  * If in text, enter the “click loop” 
  * otherwise, handle scroller or bleed 
  * click.
  */
 if(in_text)
 TEClick(&Event.where, 0, te_handle);
 else
 {
 part = 
 (short)FindControl(&Event.where,
 (*te_handle)->inPort, &ch);
 switch(part)
 {
 case inUpButton:
 TrackControl(ch, &Event.where,
 scroll_up);
 break;

 case inDownButton:
 TrackControl(ch, &Event.where,
 scroll_down);
 break;

 case inPageUp:
 page_scroll(part, ch, -1);
 break;

 case inPageDown:
 page_scroll(part, ch, 1);
 break;
 
 case inThumb:
 TrackControl(ch, &Event.where,
 0);
 edit_scroll();

 default: /* In bleed */
 }
 }
 }

How to Handle Scrolling

The Easy Way

There are several mystery functions in the code given above. First, and most important, is edit_scroll(). It is the basis for all of the other mystery functions. But before we go into the mechanics of “easy scrolling”, lets look at the basic method.

The key to the method is the relationship between the scroll bar’s “control value” and the position of the displayed text. Recall that TEScroll takes relative horizontal and vertical scroll distances, movement amounts. To nail things down, we first define a coordinate pair (a Point) which will contain the distance in pixels that we have scrolled from the original top left. We’ll call this te_origin.

Now for the main thing. The scroller “values” are used to control the values of te_origin’s vertical and horizontal coord- inates. The range of values for the horizontal scroller is destRect.left to destRect.right. Likewise, the range of values for the vertical scroller is destRect.top to destRect.bottom. Think about that one ...

Any time a scroller’s value changes, the new value is compared with the corresponding value of te_origin. The difference is used to call TEScroll() to do the actual scrolling, then the new value replaces the old value in te_origin. Here is the C code to implement this basic scrolling function (please don’t criticize this for tightness, it’s an example):

/*
 * edit_scroll()
 *
 * Inputs:
 * Current value of te_origin
 * Current values of the scrollers
 *
 * Outputs:
 * te_origin is updated
 * Window is scrolled to new loc
 *
 * WARNING - untested extract
 */
edit_scroll()
   {
   short int nh, nv, dh, dv;
 
   nh = GetCtlValue(hs_handle);
   if(nh < 4) nh = 4;
   dh = te_origin.h - nh;
   te_origin.h -= dh;

   nv = GetCtlValue(vs_handle);
   if(nv < 4) nv = 4;
   dv = te_origin.v - nv;
   te_origin.v -= dv;

   #TEScroll(dh, dv,te_handle);
   }

This function is all we need to handle the “inThumb” case of scrolling in the content_click() routine above. A click in the thumb causes us to call TrackControl(), which keeps control until the mouse is released. At that point we get control back and immediately call edit_scroll(), which reads the control values and scrolls as required.

The next case to handle is clicking in the up and down buttons. For the vertical scroller, the proper action is to repeatedly scroll one “lineHeight” until the mouse is released. For the hori- zontal scroller, you might choose a “jump” scroll of 1/8 of the window width or something like that.

The proper way to accomplish this repeated scrolling action is to do so with an action routine supplied to the TrackControl() function. These are the mystery scroll_up() and scroll_down() functions used in content_click() above. Unfortunately, they cannot be written in C. This is because they are “called back” from the TrackControl() function, and the callback uses the LisaPascal linkage interface. Here is the assembly code for the vertical scroller’s scroll_up():

;
; scroll_up()
;
; TrackControl callback action routine for
; vertical scroller’s scroll-up one line
; function.  Called when up-arrow is
; pressed.
;
; Inputs:
;   4(sp) Part code (short int)
;   6(sp) ControlHandle (32-bit address)
;
scroll_up:
 Link A6,#0 ; Link env.
 Move.W 8(A6),D0 ; D0 = part code (W)
 Beq  @1; (not in arrow now)
 Move.L 10(A6),-(SP) ; Save handle
 Clr.W  -(sp)  ; Gets control value
 Move.L 10(A6),-(SP) ; Pass handle
 _GetCtlValue  ; Get the value
 ; ------------------
 Jsr  get_lh; D0 = line height
 Sub.W  D0,(SP)  ; (SP) = new ctl val
 Bge  @0; (OK, its positive)
 Clr.W  (SP); Limit at 0
@0:; ------------------
 _SetCtlValue  ; Set new value
 Jsr  edit_scroll ; Now scroll
@1:
 Unlk a6; Pascal exit
 Move.L (SP)+,A0
 Addq #6,SP
 Jmp  (A0)

Note the statements between the dashed lines. This is the only difference between the horizontal and vertical scroller’s callback routines for up and down. The difference is in the amount and direction of change to the scroller’s value in (SP). The example above makes use of a mystery routine get_lh(), which reads the line height from the TERec. It also calls our edit_scroll() routine to scroll the window once the scroller’s value has been changed. The call to _SetCtlValue changes the value of the scroller and moves the thumb box accordingly.

The final thing we need is a routine for page scrolling. This time, we won’t use TrackControl(). Since we are not being called back, the routine can be written in C, and can take a “direction” parameter so one routine is all that is needed.

The Macintosh Interface Guidelines specify a particular type of “action” that we must implement in the page_scroll() routine. That is, the page scroll must be done at least once, and repeated as long as the mouse is held down and the point is inside the original page scroll area. If the mouse is moved out of that page scroll area, page scrolling should stop, until it is moved back into the area, at which time page scrolling should resume.

The following page scrolling routine does this and scrolls different amounts for vertical and horizontal scrollers. See if you can figure out what is happening:

/*
 * page_scroll()
 *
 * Inputs:
 *  partPart code where first clicked
 *  ch  ControlHandle
 *  dir Direction: -1=Up  1=Down
 *
 * Locks the TERec temporarily
 */
page_scroll(part, ch, dir)
short part;
ControlHandle ch;
short dir;
 {
 Point cur_pt;
 short amount;
 Rect *vr;

 HLock(te_handle); /* Lock & deref */

 vr = &((*(te_handle))->viewRect);
 if(ch = vs_handle)
 amount = vr_bottom - vr->top -
 (short)get_lh();
 else
 amount = (vr->right - vr->left)/2;

 amount *= dir;

 /*
  * Act in accordance with Interface
  * Guidelines.
  */
 do{
 GetMouse(&cur_pt);
 if((short)TestControl(ch, &cur_pt)
    != part)
 continue;
 SetCtlValue(ch, GetCtlValue() +      amount);
 edit_scroll();
 } while(StillDown());
 
 HUnlock(ch);  /* Release TERec */
 }

That’s about it for scrolling. There’s a lot of hidden information in the routines given. If you’ll take the time to understand them (and the associated toolbox traps), you will have a great start at one of the most complex areas of Mac application design.

Event Handling: Updates

Handling update events for document windows is surprisingly simple. TextEdit and the Control Manager do most of the work. Update events call for redrawing the window’s contents. BeginUpdate() and EndUpdate() restrict the actual drawing to that which is necessary. Here is an example of an update event handler for document window:

/*
 * Upd_wind() - Update document window
 *
 * Inputs:
 * wp = WindowPointer
 * th = TEHandle
 */
upd_wind(wp, th)
WindowPtr wp;
TEHandle th;
 {
 
 BeginUpdate();
 SetPort(wp);

 DrawGrowIcon(wp);
 DrawControls(wp);
 TEUpdate(&((*(wp->visRgn))->rgnBBox), th);
 
 EndUpdate();
 }

That’s it. Notice the rectangle passed to TEUpdate(). Instead of drawing the entire ViewRect, this method uses the visRgn, which has been temporarily hacked to be the update region by BeginUpdate(). This is one case where it is easy to manually restrict drawing to the update region. Doing this can result in substantial speed improvements for TEUpdate. Notice how easy it is to redraw the controls.

Event Handling:

Activate and Deactivate

Activation (and deactivation) events are also quite easy to handle for document windows. Activation calls for changing the “look” of the controls and text, and turning on the caret or selection range. Actually, for scrollers, activa- tion means “showing” them, deactivation means “hiding” them.

There is no “ShowControls()” function so we “show” each one by tracing down the linked list. This method makes it unnecessary to pass control handles:

/*
 * act_wind()/deact_wind()
 *
 * Activate event handlers
 */
act_wind(wp)
WindowPtr wp;
 {
 Handle ch;

 SetPort(wp);

 DrawGrowIcon(wp);
 TEActivate(dp->te_handle)
 ch = ((WindowPeek)(wp))->controlList; while(ch != NULL)
 {
 ch = 
   (*((ControlHandle)(ch)))->nextControl)
 ShowControl(ch);
 }
 }

deact_wind(wp)
WindowPtr wp;
 {
 Handle ch;

 SetPort(wp);

 DrawGrowIcon(wp);
 TEDeactivate(dp->te_handle)
 ch = ((WindowPeek)(wp))->controlList; while(ch != NULL)
 {
 ch = 
   (*((ControlHandle)(ch)))->nextControl)
 HideControl(ch);
 }
 }

Note that each routine calls DrawGrowIcon(). That function knows whether the window is active or inactive, and fills in the grow box appropriately. In other words, DrawGrowIcon() for an inactive window blanks out the grow box.

Final Words

As promised last month, I have used TextEdit and controls to tie together the information given in the last two issues, and to illustrate applications of basic Mac principles. The routines shown in this month’s column are untested examples! In most cases, the code was lifted out of working applications, then simplified for ease of understanding. The algorithms should be correct, the detail may not be.

Due to the size of even a simple C application, we won’t be publishing sources for complete applications in MacTutor. Rather, we’ll make them available on the MacTutor source disks.

I plan to devote next month to a random collection of operating system hacks, maybe an interface to Standard File or a C implementation of sprintf() for those of us who abhor Unix libraries for Mac applications.

Heinich “Benchmark” Revisited

In the February 1985 edition of MacTutor, we published this program sent in by Mr. Robert Heinich of Boca Raton, FL:

main()
{
union u_storage{
  long a_long;
  struct T_0000{
    short a_short;
    short b_short;
  }S_0000;
}storage;
storage.a_long = 6;
printf(“\na_short = %d”,
  storage.S_0000.a_short);
printf(“\nb_short = %d”,
  storage.S_0000.b_short);
printf(“\n”);
}

He was looking for the answers “a_short = 0” and “b_short = 6”. The nature of this program compels me to make some comments.

The union maps 2 16-bit words over a 32-bit longword. The order of addressing the two words in the longword is system-dependent.

The 68000 stores the least significant byte of a word at address n and the most significant half at address n+1. Likewise, it stores the most significant half of a longword at address n and the least significant half at address n+2 . It is this latter property that the program uncovers.

Other machines (such as the DEC PDP-11 and VAX systems) store words and bytes in the reverse order. There are sound reasons for each convention and I’ll not argue either point.

What this program has brought up is the “discussion” of whether or not the C language should hide such machine dependencies from the programmer.

Firstly, the current C languages do not hide machine dependencies. The new ANSI standard does not call for machine independence either.

Some people feel that C is a high-level language and therefore a C program written for machine X should run on any other machine (except for OS specific, of course).

I couldn’t disagree more. C is a “system implementation” language. The whole idea of C is to amplify the programmer’s productivity and enhance maintainability by providing a viable alternative to assembly language.

If C compilers scrambled the addressing of struct members, it would make the language nearly impossible to use for system programming. In fact, there are many people who feel that automatic padding to insure correct alignment of structure members is not good. The Mac C compiler has an option to control structure padding.

C provides a well-defined access to low-level machine specifics. I don’t want that to change.

 
AAPL
$99.02
Apple Inc.
+1.35
MSFT
$43.97
Microsoft Corpora
-0.53
GOOG
$590.60
Google Inc.
+1.58

MacTech Search:
Community Search:

Software Updates via MacUpdate

OS X Yosemite Wallpaper 1.0 - Desktop im...
OS X Yosemite Wallpaper is the gorgeous new background image for Apple's upcoming OS X 10.10 Yosemite. This wallpaper is available for all screen resolutions with a source file that measures 5,418... Read more
Acorn 4.4 - Bitmap image editor. (Demo)
Acorn is a new image editor built with one goal in mind - simplicity. Fast, easy, and fluid, Acorn provides the options you'll need without any overhead. Acorn feels right, and won't drain your bank... Read more
Bartender 1.2.20 - Organize your menu ba...
Bartender lets you organize your menu bar apps. Features: Lets you tidy your menu bar apps how you want. See your menu bar apps when you want. Hide the apps you need to run, but do not need to... Read more
TotalFinder 1.6.2 - Adds tabs, hotkeys,...
TotalFinder is a universally acclaimed navigational companion for your Mac. Enhance your Mac's Finder with features so smart and convenient, you won't believe you ever lived without them. Tab-based... Read more
Vienna 3.0.0 RC 2 :be5265e: - RSS and At...
Vienna is a freeware and Open-Source RSS/Atom newsreader with article storage and management via a SQLite database, written in Objective-C and Cocoa, for the OS X operating system. It provides... Read more
VLC Media Player 2.1.5 - Popular multime...
VLC Media Player is a highly portable multimedia player for various audio and video formats (MPEG-1, MPEG-2, MPEG-4, DivX, MP3, OGG, ...) as well as DVDs, VCDs, and various streaming protocols. It... Read more
Default Folder X 4.6.7 - Enhances Open a...
Default Folder X attaches a toolbar to the right side of the Open and Save dialogs in any OS X-native application. The toolbar gives you fast access to various folders and commands. You just click... Read more
TinkerTool 5.3 - Expanded preference set...
TinkerTool is an application that gives you access to additional preference settings Apple has built into Mac OS X. This allows to activate hidden features in the operating system and in some of the... Read more
Audio Hijack Pro 2.11.0 - Record and enh...
Audio Hijack Pro drastically changes the way you use audio on your computer, giving you the freedom to listen to audio when you want and how you want. Record and enhance any audio with Audio Hijack... Read more
Intermission 1.1.1 - Pause and rewind li...
Intermission allows you to pause and rewind live audio from any application on your Mac. Intermission will buffer up to 3 hours of audio, allowing users to skip through any assortment of audio... Read more

Latest Forum Discussions

See All

Traps n’ Gemstones Review
Traps n’ Gemstones Review By Campbell Bird on July 28th, 2014 Our Rating: :: CASTLEVANIA JONESUniversal App - Designed for iPhone and iPad Fight mummies, dig tunnels, and ride a runaway minecart to discover ancient secrets in this... | Read more »
The Phantom PI Mission Apparition Review
The Phantom PI Mission Apparition Review By Jordan Minor on July 28th, 2014 Our Rating: :: GHOSTS BUSTEDUniversal App - Designed for iPhone and iPad The Phantom PI is an exceedingly clever and well-crafted adventure game.   | Read more »
More Stubies Are Coming Your Way in a Ne...
More Stubies Are Coming Your Way in a New Update Posted by Jessica Fisher on July 28th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
The Great Prank War Review
The Great Prank War Review By Nadia Oxford on July 28th, 2014 Our Rating: :: PRANKING IS SERIOUS BUSINESSUniversal App - Designed for iPhone and iPad Though short, The Great Prank War offers an interesting and fun mix of action and... | Read more »
Marvel Contest of Champions Announced at...
Marvel Contest of Champions Announced at Comic-Con Posted by Jennifer Allen on July 28th, 2014 [ permalink ] Announced over the weekend at San Diego Comic-Con was the fairly exciting looking Marvel Contest of Champions. | Read more »
Teenage Mutant Ninja Turtles Review
Teenage Mutant Ninja Turtles Review By Jennifer Allen on July 28th, 2014 Our Rating: :: DULL SWIPINGUniversal App - Designed for iPhone and iPad The pizza power is weak when it comes to this Teenage Mutant Ninja Turtles game.   | Read more »
Exploration Focused Puzzle Game Beatbudd...
Exploration Focused Puzzle Game Beatbuddy Set to Make Transition from PC to iOS this September Posted by Jennifer Allen on July 28th, 2014 [ permalink ] | Read more »
PlanetHD
PlanetHD By Nadia Oxford on July 28th, 2014 Our Rating: :: SPACE MADNESSUniversal App - Designed for iPhone and iPad PlanetHD will keep players busy for a while, though its unpredictable physics are a handful to deal with.   | Read more »
This Week at 148Apps: July 21-25, 2014
Another Week of Expert App Reviews   At 148Apps, we help you sort through the great ocean of apps to find the ones we think you’ll like and the ones you’ll need. Our top picks become Editor’s Choice, our stamp of approval for apps with that little... | Read more »
Reddme for iPhone - The Reddit Client (...
Reddme for iPhone - The Reddit Client 1.0 Device: iOS iPhone Category: News Price: $.99, Version: 1.0 (iTunes) Description: Reddme for iPhone is an iOS 7-optimized Reddit client that offers a refreshing new way to experience Reddit... | Read more »

Price Scanner via MacPrices.net

Apple updates MacBook Pros with slightly fast...
Apple updated 13″ and 15″ Retina MacBook Pros today with slightly faster Haswell processors. 13″ models now ship with 8GB of RAM standard, while 15″ MacBook Pros ship with 16GB across the board. Most... Read more
iOS 8 and OS X 10.10 To Support DuckDuckGo As...
Writing for Quartz, Dan Frommer reports that Apple’s forthcoming iOS 8 and OS X 10.10 operating systems version updates will allow users to select DuckDuckGo as their default search engine. He notes... Read more
U.K. Hospital Using iPods and iPads To Record...
British news journal GazetteLive’s. Ian McNeal notes that the old “an apple a day keeps the doctor away” proverb is being turned on its head at http://southtees.nhs.uk/hospitals/james-cook/ James... Read more
13-inch 2.5GHz MacBook Pro on sale for $1099,...
Best Buy has the 13″ 2.5GHz MacBook Pro available for $1099.99 on their online store. Choose free shipping or free instant local store pickup (if available). Their price is $100 off MSRP. Price is... Read more
Roundup of Apple refurbished MacBook Pros, th...
The Apple Store has Apple Certified Refurbished 13″ and 15″ MacBook Pros available for up to $400 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free. Their prices... Read more
Record Mac Shipments In Q2/14 Confound Analys...
A Seeking Alpha Trefis commentary notes that Apple’s fiscal Q3 2014 results released July 22, beat market predictions on earnings, although revenues were slightly lower than anticipated. Apple’s Mac’... Read more
Intel To Launch Core M Silicon For Use In Not...
Digitimes’ Monica Chen and Joseph Tsai, report that Intel will launch 14nm-based Core M series processors specifically for use in fanless notebook/tablet 2-in-1 models in Q4 2014, with many models to... Read more
Apple’s 2014 Back to School promotion: $100 g...
 Apple’s 2014 Back to School promotion includes a free $100 App Store Gift Card with the purchase of any new Mac (Mac mini excluded), or a $50 Gift Card with the purchase of an iPad or iPhone,... Read more
iMacs on sale for $150 off MSRP, $250 off for...
Best Buy has iMacs on sale for up to $160 off MSRP for a limited time. Choose free home shipping or free instant local store pickup (if available). Prices are valid for online orders only, in-store... Read more
Mac minis on sale for $100 off MSRP, starting...
Best Buy has Mac minis on sale for $100 off MSRP. Choose free shipping or free instant local store pickup. Prices are for online orders only, in-store prices may vary: 2.5GHz Mac mini: $499.99 2.3GHz... Read more

Jobs Board

Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Sr. Product Leader, *Apple* Store Apps - Ap...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.