TweetFollow Us on Twitter

Jul 98 Getting Started

Volume Number: 14 (1998)
Issue Number: 7
Column Tag: Getting Started

Using The List Manager

by Dave Mark and Dan Parks Sydow

Before we get into this month's column, I would like to take a moment to introduce my friend and collaborator, Dan Sydow. You might know Dan from his many Mac programming books. Over the coming months, Dan and I will work together to produce the monthly Getting Started column. I think Dan will help broaden the perspective of the column. I hope you enjoy this collaboration as much as we do!
--Dave Mark

How a Mac program handles lists

In recent columns, you've learned the very basics of Mac programming, including how to write event-based applications that make use of windows. Last month we moved beyond the basics to look at dialog filters. Now it's time to continue on the path of covering slightly more involved topics. This month we study the list. Including a list in a window is a common practice in Mac programs. The list is a powerful tool that allows the user to easily make his or her wishes known to the program. And while implementing a list is a little more complex than, say, adding a button to a dialog box, in this column you'll see that the List Manager provides a big assist.

The List Manager

The List Manager is the part of the Macintosh Toolbox that allows you to create and manage scrollable lists. Such a list allows users to select an item from a group of items. The vast majority of Macintosh applications make use of the List Manager, albeit indirectly. The standard Open dialog box common to programs that allow the user to choose a file to open holds a list created and governed by the List Manager. Figure 1 shows the result of a call to the Toolbox function StandardGetFile().

Figure 1. The List Manager, as used by StandardGetFile().

The dialog box shown in Figure 1 is the product of calls to List Manager functions that display the list of files to open, and Dialog Manager functions that create the dialog box that houses the list. StandardGetFile() shields all these calls from you, the programmer. In this article we'll dig a little deeper and see how to make use of the List Manager directly to place a list in a window of our own creation.


This month's program is PictLister -- a program designed to showcase the List Manager. PictLister lets you create a window listing all the PICT resources available to your program. The available resources include those in the application's own resource fork, as well as those present in any resource files that the System has open. An example of the latter is the System file's own resource fork, which is always open and accessible by applications. The window on the left side of Figure 2 includes a list that shows the PICT resources found by my copy of PictLister.

Figure 2. A PictLister window.

To demonstrate how user-interaction with a list takes place, double-clicking on the name of a PICT resource causes PictLister to display the selected picture in its own window. Figure 2 shows the picture-displaying window that appears when the Party Hats item is selected in from the list in the Picture List window.

Creating the PictLister Resources

Start by creating a folder named PictLister inside your development folder. Fire up ResEdit and create a file named PictLister.rsrc inside your PictLister folder.

PictLister needs one menu bar resource and three menu resources in order to display its menu bar. Begin by creating an MBAR resource with an ID of 128. The MBAR should list three MENU resource IDs: 128, 129, and 130. Create three MENU resources according to the specifications in Figure 3. Be sure to include a separator line as the third item in the File menu.

Figure 3. The three MENU resources.

You'll need to create two WIND resources. The first WIND has an ID of 128, and defines the properties of the list window. Create this WIND based on the specifications shown in Figure 4. Note that the Close box check box is unchecked. Because the list window is the heart of the PictLister program, it doesn't include a close box -- it remains on screen until the user quits.

Figure 4. The list window WIND resource.

Any time a picture is displayed in PictLister, it's displayed in the same window -- a window based on a WIND resource with an ID of 129. The picture window won't be resizable, so after you create this WIND, click on the icon second from the left in the row of small window icons located at the top of the WIND (it doesn't include a size box). The picture window is closeable, so check the Close box check box. Set the location and size of the window to any reasonable values -- PictLister will be resizing the window as the program runs.

Now add any number of PICT resources to the resource file. Go into the scrapbook (or your favorite graphics application) and use Copy and Paste to create a series of PICT resources in the resource file. When finished, double-click on the icon labeled PICT in the PictLister.rsrc file to open a window that displays each picture. One-by-one, click on a PICT resource, select Get Resource Info from the Resource menu, type in a name, and check the Purgeable check box. That last step gives the system to free up the memory the picture occupies when the picture data has been loaded but isn't in use. Figure 5 shows the Get Resource Info window for my first PICT resource.

Figure 5. Get Resource Info for my first PICT resource.

It's important to name your PICT resources, since PictLister uses the PICT's name to represent the PICT in a PictLister window (refer back to Figure 2 to see an example).

Creating the PictLister Project

If you haven't saved the resource file and quit ResEdit, do so now. Launch CodeWarrior and create a new project based on the MacOS:C_C++:MacOS Toolbox:MacOS Toolbox 68Kstationary. Uncheck the Create Folder check box. Name the project PictLister.mcp and place it in your PictLister folder. Remove SillyBalls.c and SillyBalls.rsrc from the project; we will not be using these files in this project. From the Finder, drag and drop your PictLister.rsrc file into the project window. Click the OK button if you see the Add Files dialog box. Our project won't be using any of the standard ANSI libraries, so you can remove a little clutter by dragging the ANSI Libraries folder from the project window to your desktop's Trash can.

Choose New from the File menu to create a new source code window. Save it with the name PictLister.c, then select Add Window from the Project menu to add this new file to your project. Now your project window should look similar to mine -- the one pictured in Figure 6.

Figure 6. PictLister project window.

Now it's time to type in the PictLister code in the PictLister.c file. You can do as you read the through the following source code walk-through, or you can greatly reduce your efforts by downloading the whole project from MacTech's ftp site

Walking Through the Source Code

PictLister makes use of code that's been discussed in recent columns, so our explanation of things like the event loop and window creation is light. Instead, the focus is on list-related code.

PictLister starts off with a bunch of #defines, some familiar, some not. As usual, you'll see what they do in context.

/********************* constants *********************/

#define kSleep            7
#define kMoveToFront      (WindowPtr)-1L

#define kListDefProc      0
#define kDrawIt           true
#define kHasGrow          true
#define kHasHScroll       true
#define kHasVScroll       true
#define kFindNext         true

#define kMinWindWidth     150
#define kMinWindHeight    60
#define kWindOrigWidth    200
#define kWindOrigHeight   255

#define kBaseResID        128
#define kListWindID       kBaseResID
#define kPictureWindID    kBaseResID+1

#define mApple            kBaseResID
#define iAbout            1

#define mFile             kBaseResID+1
#define iQuit             1

The global variable gDone serves its usual role, indicating when it's time to drop out of the main event loop. There will be just one list window open at all times, so it makes sense to declare the global WindowPtr variable gListWindow to keep track of it. The ListHandle variable gListHandle makes it easy to access the list window's list at any time. A similar situation exists for the picture window: gPictWindow lets us access the picture window, while gCurrentPicture provides a means of working with the window's picture.

/********************** globals **********************/

Boolean       gDone;
WindowPtr     gListWindow = NULL;
ListHandle    gListHandle = NULL;
WindowPtr     gPictWindow = NULL;
PicHandle     gCurrentPicture = NULL;

As usual, we provide a function prototype for each function in the source file.

/********************* functions *********************/
void   ToolBoxInit( void );
void   MenuBarInit( void );
void   CreatePictureWindow( void );
void   CreateListWindow( void );
void   EventLoop( void );
void   DoEvent( EventRecord *eventPtr );
void   HandleMouseDown( EventRecord *eventPtr );
void   DoContentClick(   EventRecord *eventPtr, 
                           WindowPtr window );
void   SetWindowPicture( void );
void   DoGrow( EventRecord *eventPtr, WindowPtr window );
void   DoUpdate( EventRecord *eventPtr );
void   DoActivate( WindowPtr window, Boolean becomingActive );
void   HandleMenuChoice( long menuChoice );
void   HandleAppleChoice( short item );
void   HandleFileChoice( short item );

The main() routine initializes the Toolbox, sets up the menu bar, opens a couple of windows, then enters the main event loop.

/************************ main ***********************/

void   main( void )

ToolboxInit() does its usual thing.

/******************** ToolBoxInit ********************/

void   ToolBoxInit( void )
   InitGraf( &qd.thePort );
   InitDialogs( nil );

MenuBarInit() is no different than previous versions: it loads the MBAR, adds the normal resources to the Apple menu, and draws the menu bar.

/******************** MenuBarInit ********************/

void   MenuBarInit( void )
   Handle            menuBar;
   MenuHandle      menu;
   menuBar = GetNewMBar( kBaseResID );
   SetMenuBar( menuBar );

   menu = GetMenuHandle( mApple );
   AppendResMenu( menu, 'DRVR' );

CreatePictureWindow() creates a window that's to be used to display the picture that the user eventually will choose from the not-yet-opened list window. We'll create the window and assign it to the global variable gPictWindow here, but we won't display it just yet. You should have unchecked the Initially visible check box in WIND resource 129, but just in case you didn't the call to HideWindow() hides the window. We'll display it only after the user chooses a list item in the list window.

/**************** CreatePictureWindow ****************/

void   CreatePictureWindow( void )
   gPictWindow = GetNewWindow(   kPictureWindID, nil, 
                                             kMoveToFront );
   if ( gPictWindow == nil )
      SysBeep( 10 );    /* Couldn't load the WIND resource!!! */
   HideWindow( gPictWindow );

CreateListWindow() creates the program's one list window and assigns it to the global variable gListWindow.

/****************** CreateListWindow *****************/

void   CreateListWindow( void )
   Rect         r;
   Rect         dataBounds;
   Point      cSize, cIndex;
   short      i, dummy, numPicts;
   Handle      rHandle;
   short      resID;
   ResType   theResType;
   Str255      rName;
   gListWindow = GetNewWindow(   kListWindID, nil, 
                                          kMoveToFront );

   if ( gListWindow == nil )
      SysBeep( 10 );   /* Couldn't load the WIND resource!!! */

The font used in the display of list items is based on the current graphics port font. The call to TextFont() ensures that the list is drawn using the system font (which may be either Charcoal or Chicago, depending on the user's System Font setting in the Appearance control panel). Precede the call to TextFont() with a call to SetPort() so that the text-setting affects the list window.

   SetPort( gListWindow );
   TextFont( systemFont );

Next, we prepare to create our list. The rectangle dataBounds specifies the initial setup of the list. In this case, we're specifying a list 1 column wide and 0 rows deep. We'll add rows to the list a little later.

   SetRect( &dataBounds, 0, 0, 1, 0 );

cSize specifies the size, in pixels, of each cell in the list. By passing (0,0) as the cell size, we ask the List Manager to calculate the size for us (based on the eventual contents of the cell).

   SetPt( &cSize, 0, 0 );

Finally, r is a Rect that specifies the bounds of the list. Because the scroll bars are drawn outside this area, we allow room for them to fit between the list and the window right and bottom sides. The values of the constants kWindOrigWidth and kWindOrigHeight come from the values used in the list window WIND resource.

   SetRect (&r, 0, 0, kWindOrigWidth-15, kWindOrigHeight-15);

The list is created via a call to LNew(). LNew() accepts a list definition procedure that specifies some aspects of the list. Using a value of 0 (which we defined kListDefProc to be) specifies the use of the default list definition. The Boolean value kDrawIt tells the List Manager to enable automatic drawing mode -- a mode that has the List Manager automatically redraw the list whenever a change is made to it. The Boolean variables kHasGrow, kHasHScroll, and kHasHScroll tell the List Manager to add two scroll bars and a grow box to the list.

   gListHandle = LNew(   &r, &dataBounds, cSize, kListDefProc,
                 gListWindow, kDrawIt, kHasGrow, 
                 kHasHScroll, kHasVScroll );

LNew() returns a handle to a ListRec, the data structure representing the list. We store this handle in the global variable gListHandle to be used throughout the program.

The selFlags field of a ListRec lets you specify how the list reacts to clicks in the list. We'll use the flag lOnlyOne to tell the List Manager that only one item at a time can be highlighted in this list.

   (**gListHandle).selFlags = lOnlyOne;

This next chunk of code adds the rows to the list. We'll add one row to the list for every available PICT resource.

   numPicts = CountResources( 'PICT' );
   for ( i = 0; i < numPicts; i++ )

For each resource, retrieve the resource handle using GetIndResource(), then call GetResInfo() to retrieve the resource name, if it exists.

   rHandle = GetIndResource( 'PICT', i + 1 );
   GetResInfo( rHandle, &resID, &theResType, rName );

LAddRow() adds one row to the list specified by gListHandle. cIndex is set to the cell in the first (and only) column and in the ith row.

   dummy = LAddRow( 1, i, gListHandle );
   SetPt( &cIndex, 0, i );

Next, the data is added to the cell specified by cIndex. If the resource is not named, the string "<Unnamed>" is used instead.

   if ( rName[ 0 ] > 0 )
      LAddToCell( &(rName[1]), rName[0], cIndex, gListHandle );
      LAddToCell( "<Unnamed>", 10, cIndex, gListHandle );

Next, the window is made visible, and LSetDrawingMode() is called to enable drawing in the list. This doesn't mean that the list will be drawn at this point. Instead, the next time the List Manager is asked to draw the list (perhaps via a call to LUpdate()), it will be able to.

   ShowWindow( gListWindow );
   LSetDrawingMode( true, gListHandle );

EventLoop() looks and behaves as it has in previous articles -- there are no surprises here.

/********************* EventLoop *********************/

void   EventLoop( void )
   EventRecord      event;
   gDone = false;
   while ( gDone == false )
      if ( WaitNextEvent( everyEvent, &event, kSleep, NULL ) )
         DoEvent( &event );

DoEvent() dispatches the specified event. Again, this routine remains as we've developed it in recent articles.

/********************** DoEvent **********************/

void   DoEvent( EventRecord *eventPtr )
   char   theChar;
   Boolean   becomingActive;
   switch ( eventPtr->what )
      case mouseDown: 
         HandleMouseDown( eventPtr );
      case keyDown:
      case autoKey:
         theChar = eventPtr->message & charCodeMask;
         if ( (eventPtr->modifiers & cmdKey) != 0 ) 
            HandleMenuChoice( MenuKey( theChar ) );
      case updateEvt:
         DoUpdate( eventPtr );
      case activateEvt:
         becomingActive = (   (eventPtr->modifiers & activeFlag) 
                                    == activeFlag );
         DoActivate(   (WindowPtr)eventPtr->message, 
                           becomingActive );

Most of HandleMouseDown() should look familiar to you.

/******************* HandleMouseDown *****************/

void   HandleMouseDown( EventRecord *eventPtr )
   WindowPtr   window;
   short       thePart;
   long        menuChoice;
   thePart = FindWindow( eventPtr->where, &window );
   switch ( thePart )
      case inMenuBar:
         menuChoice = MenuSelect( eventPtr->where );
         HandleMenuChoice( menuChoice );
      case inSysWindow : 
         SystemClick( eventPtr, window );
      case inContent:
         DoContentClick( eventPtr, window );
      case inGrow:
         DoGrow( eventPtr, window );
      case inDrag : 
         DragWindow(   window, eventPtr->where, 
                           &qd.screenBits.bounds );

The one exception is the call to HideWindow() when the mouse is clicked in the go away box of the picture window. Rather than destroy the window when the user opts to close it, PictLister simply hides it. As you'll see ahead, when the user double-clicks on an item in the list window list, we'll again show the now-hidden window. PictLister doesn't allow the list window to be closed, so we won't include any list window closing code here (doing so would be as easy as omitting the check to see which window was being closed).

      case inGoAway:
         if ( TrackGoAway( window, eventPtr->where ) )
            if ( window == gPictWindow )
               HideWindow( window );

DoContentClick() is called when the mouse is clicked in the specified window's content region. DoContentClick() begins by checking to see if the clicked-on window is the frontmost window. If it's not, SelectWindow() is called to bring the window to the front.

/******************* DoContentClick ******************/

void   DoContentClick( EventRecord *eventPtr, WindowPtr window )
   if ( window != FrontWindow() )
      SelectWindow( window );

If the click was in the frontmost window and the window is a list window, we'll convert the current mouse coordinates (which are in global coordinates) to the window's local coordinate system.

   else if ( window == gListWindow )
      SetPort( window );
      GlobalToLocal( &(eventPtr->where) );

Next, a call to LClick() is made. This routine handles all types of clicks, from clicks in the scroll bars to clicks in the list cells. LClick() returns true if a double-click occurs. In that case, we'll invoke the application-defined routine SetWindowPict() to determine which picture is to be displayed in the picture window.

      if ( LClick(   eventPtr->where, eventPtr->modifiers,
                        gListHandle ) )

SetWindowPicture() performs a number of tasks -- a handful of local variables help out here.

/***************** SetWindowPictWindow ***************/

void   SetWindowPicture( void )
   Cell      cell;
   Handle    rHandle;
   Rect      r;
   short     resID;
   ResType   theResType;
   Str255    rName;
   short     pictWidth;
   short     pictHeight;

The first chore is to figure out which of the list's cells is selected. We'll start by setting cell to identify the first cell in the list.

   SetPt( &cell, 0, 0 );

LGetSelect() starts at cell, then moves through the list until it finds a cell that is highlighted. If LGetSelect() finds a highlighted cell, it puts the cell's coordinates in cell and returns true.

   if ( LGetSelect( kFindNext, &cell, gListHandle ) )

If a highlighted cell was found, we'll first hide the picture window to give the appearance that we're closing the current picture window in order to open a new one.

      HideWindow( gPictWindow );

Now we'll use cell.v to retrieve the appropriate PICT resource. Notice that cell is zero-based, while GetIndResource() is one-based. We'll also store a reference to the picture in the global variable gCurrentPicture.

      rHandle = GetIndResource( 'PICT', cell.v + 1 );
      gCurrentPicture = (PicHandle)rHandle;

We'll be basing the size of the picture window on the size of the picture, so here we store the size of the picture in Rect variable r. The local variables pictWidth and pictHeight will help out in sizing the window.

      r = (**gCurrentPicture).picFrame;
      pictWidth = r.right - r.left;
      pictHeight = r.bottom -;

Next, a call to GetResInfo() is made to get the PICT resource's name. We then use that name in a call to SetWTitle() to set the picture window's title. If the PICT was unnamed, we simply use the string "<Unnamed>" for the window's title.

      GetResInfo( rHandle, &resID, &theResType, rName );

      if ( rName[ 0 ] > 0 )
         SetWTitle( gPictWindow, rName );
         SetWTitle( gPictWindow, "\p<Unnamed>" );

Finally, we're all set to resize the window to match the picture's size, show the hidden window, and then select it so that it becomes active (highlighted).

      SizeWindow( gPictWindow, pictWidth, pictHeight, true );
      ShowWindow( gPictWindow );
      SelectWindow( gPictWindow );

DoGrow() is called when the mouse is clicked in a window's grow box.

/*********************** DoGrow **********************/

void   DoGrow( EventRecord *eventPtr, WindowPtr window )
   Rect      r;
   Cell      cSize;
   long      windSize;

If the window is a list window, we'll first establish the minimum and maximum size of the window.

   if ( window == gListWindow )
   { = kMinWindHeight;
      r.bottom = 32767;
      r.left = kMinWindWidth;
      r.right = 32767;

Next, we'll call GrowWindow(). If the window was resized, we'll call SizeWindow() to resize the window, then LSize() to let the List Manager know that the list has been resized.

      windSize = GrowWindow( window, eventPtr->where, &r );
      if ( windSize )
         SetPort( window );
         EraseRect( &window->portRect );

         SizeWindow( window,
               LoWord (windSize),
               HiWord(windSize), true );

Notice that the scroll bars are not included in the list's height and width.

         LSize( LoWord(windSize)-15,
               HiWord(windSize)-15, gListHandle );

Next, cSize is set to the current cell size in pixels (including both height and width). In its quest for efficiency, the system frequently rearranges blocks of heap memory as a program runs. Here were about to alter data in an object in the heap, so while adjusting the cell size we play it safe and lock the list data structure in memory so that the system can't move it.

         HLock( (Handle)gListHandle );
         cSize = (*gListHandle)->cellSize;
         HUnlock( (Handle)gListHandle );

Though the height of a cell hasn't changed, we're going to make our cell as wide as the window. Note that this won't always be the case (resize an Excel spreadsheet and the cells don't change size). We'll call LCellSize() to resize all the cells and InvalRect() to force an update. If you have any doubts about any of these calls, try commenting them out and see what happens.

         cSize.h = LoWord( windSize ) - 15;
         LCellSize( cSize, gListHandle );
         InvalRect( &window->portRect );

Back in DoEvent() you saw that DoUpdate() is called to handle an update event.

/********************** DoUpdate *********************/

void   DoUpdate( EventRecord *eventPtr )
   WindowPtr   window;
   Rect            r;

We'll retrieve the WindowPtr from the EventRecord. As always, we'll make sure the port is set to the window to update, and we'll sandwich our update processing code between calls to BeginUpdate() and EndUpdate().

   window = (WindowPtr)(eventPtr->message);
   SetPort( window );
   BeginUpdate( window );

If the window is the list window, we'll redraw the grow box, then call LUpdate() to let the List Manager update the list as needed. Simple, eh?

   if ( window == gListWindow )
      DrawGrowIcon( window );

      LUpdate( (**gListHandle).port->visRgn, gListHandle );      

If the window is the picture window, we'll determine the size of the picture by looking at the size of picture window's port. Recall that in SetWindowPicture() we based the size of the picture window on the size of the picture that was to be displayed in it. The picture data is referenced by the global variable gCurrentPicture, so we can go ahead and call DrawPicture() using gCurrentPicture.

   else if ( window == gPictWindow )
      r = gPictWindow->portRect;
      DrawPicture( gCurrentPicture, &r ); 

   EndUpdate( window );

DoActivate() handles activate events. Since the picture window doesn't need any special activate event processing, all we have to do is handle list window activates.

/********************* DoActivate ********************/

void   DoActivate( WindowPtr window, Boolean becomingActive )
   if ( window == gListWindow )
      if ( becomingActive )
         LActivate( true, gListHandle );
         LActivate( false, gListHandle );
      DrawGrowIcon( window );

I've save the menu-handling code for last for one reason: at this point we're home free. The remaining code, starting with HandleMenuChoice(), is all code that you've seen in recent columns. HandleMenuChoice() dispatches a menu selection. This code comes from recent columns.

/****************** HandleMenuChoice *****************/

void   HandleMenuChoice( long menuChoice )
   short   menu;
   short   item;
   if ( menuChoice != 0 )
      menu = HiWord( menuChoice );
      item = LoWord( menuChoice );
      switch ( menu )
         case mApple:
            HandleAppleChoice( item );
         case mFile:
            HandleFileChoice( item );
      HiliteMenu( 0 );

HandleAppleChoice() does what it always does. Create ALRT and DLOG ideas, then substitute appropriate alert-opening code under the iAbout case label if you want an About box to be displayed in response to the user choosing the About PictLister item under the Apple menu.

/***************** HandleAppleChoice *****************/

void   HandleAppleChoice( short item )
   MenuHandle   appleMenu;
   Str255         accName;
   short         accNumber;
   switch ( item )
      case iAbout:
         SysBeep( 10 );
         appleMenu = GetMenuHandle( mApple );
         GetMenuItemText( appleMenu, item, accName );
         accNumber = OpenDeskAcc( accName );

HandleFileChoice() dispatches selections from the File menu. Here we only need to handle one item -- Quit.

/****************** HandleFileChoice *****************/

void   HandleFileChoice( short item )
   switch ( item )
      case iQuit:
         gDone = true;

Running PictLister

Select Run from the Project menu to run PictLister. The first thing you'll see when you run PictLister is the menu bar, featuring the Apple, File, and Edit menus, and the Picture Lister window. The entire content region of the window (including both scroll bars, but not the window's title bar) is dedicated to the window's list. The items in this list consist of all available PICT resources by name. If the resource doesn't have a name, the string <Unnamed> appears.

Play with the window a bit. Resize it. Notice that there is a definite minimum size. Click on an item. Notice that the item highlights. Try scrolling the list. Click on an item and drag it down or up. If the window is small enough to enable scrolling, dragging an item up or down causes the window to auto-scroll to the top or bottom of the list. With very little effort on our part (just a call here or there) the List Manager handles the scroll bars, clicks in the list, auto-scrolling, update events, and so forth. The List Manager gives you a lot of functionality with very little work on your part.

Double-click on an item in the list. A new window appears containing the named PICT. Double-click on another list item and it appears that the picture window closes and a new picture window holding the newly selected PICT opens. You know now that what actually is occurring is that the picture window is hidden, resized to the dimensions of the just-selected PICT, and then reshown. Closing the picture window by clicking on its close box simply hides the window.

Till Next Month

Next month, we'll delve deep into windows. Not the "ordinary" windows we've been working with all along, but rather ones of a "roll your own" variety. A window definition (WDEF) allows you to define a window with any look you want -- even a look that doesn't conform to any typical Macintosh window.

Until next month, look over the PictLister code and read up on the List Manager. Check out the List Manager chapter in Inside Macintosh: More Macintosh Toolbox for more details. Then experiment with the PictLister source code. For instance, you might want to try adding this feature to the program: Instead of using the string <Unnamed> to name unnamed PICT resources, try creating a string containing the resource's resource ID, using the string both in the list window and in the PICT window's title. See you next month...

Dan Parks Sydow is the author of over a dozen programming books, including Foundations of Mac Programming by IDG Books. Dan's lending a hand on this Getting Started article.


Community Search:
MacTech Search:

Software Updates via MacUpdate

Parallels Desktop 12.0.0 - Run Windows a...
Parallels allows you to run Windows and Mac applications side by side. Choose your view to make Windows invisible while still using its applications, or keep the familiar Windows background and... Read more
Firefox 48.0.2 - Fast, safe Web browser.
Firefox offers a fast, safe Web browsing experience. Browse quickly, securely, and effortlessly. With its industry-leading features, Firefox is the choice of Web development professionals and casual... Read more
Apple iOS 9.3.5 - The latest version of...
iOS is the world’s most advanced mobile operating system, and it’s the foundation of iPhone, iPad, and iPod touch. It comes with a collection of apps and features that let you do the everyday things... Read more
Spotify - Stream music, crea...
Spotify is a streaming music service that gives you on-demand access to millions of songs. Whether you like driving rock, silky R&B, or grandiose classical music, Spotify's massive catalogue puts... Read more
Apple iOS 9.3.5 - The latest version of...
iOS is the world’s most advanced mobile operating system, and it’s the foundation of iPhone, iPad, and iPod touch. It comes with a collection of apps and features that let you do the everyday things... Read more
Parallels Desktop 12.0.0 - Run Windows a...
Parallels allows you to run Windows and Mac applications side by side. Choose your view to make Windows invisible while still using its applications, or keep the familiar Windows background and... Read more
Spotify - Stream music, crea...
Spotify is a streaming music service that gives you on-demand access to millions of songs. Whether you like driving rock, silky R&B, or grandiose classical music, Spotify's massive catalogue puts... Read more
Firefox 48.0.2 - Fast, safe Web browser.
Firefox offers a fast, safe Web browsing experience. Browse quickly, securely, and effortlessly. With its industry-leading features, Firefox is the choice of Web development professionals and casual... Read more
BBEdit 11.6.1 - Powerful text and HTML e...
BBEdit is the leading professional HTML and text editor for the Mac. Specifically crafted in response to the needs of Web authors and software developers, this award-winning product provides a... Read more
OmniGraffle Pro 6.6.1 - Create diagrams,...
OmniGraffle Pro helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use... Read more

Cartoon Network Superstar Soccer: Goal!!...
Cartoon Network Superstar Soccer: Goal!!! – Multiplayer Sports Game Starring Your Favorite Characters 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Become a soccer superstar with your... | Read more »
NFL Huddle: What's new in Topps NFL...
Can you smell that? It's the scent of pigskin in the air, which either means that cliches be damned, pigs are flying in your neck of the woods, or the new NFL season is right around the corner. [Read more] | Read more »
FarmVille: Tropic Escape tips, tricks, a...
Maybe farming is passé in mobile games now. Ah, but farming -- and doing a lot of a other things too -- in an island paradise might be a little different. At least you can work on your tan and sip some pina coladas while tending to your crops. [... | Read more »
Become the King of Avalon in FunPlus’ la...
King Arthur is dead. Considering the legend dates back to the 5th century, it would be surprising if he wasn’t. But in the context of real-time MMO game King of Avalon: Dragon Warfare, Arthur’s death plunges the kingdom into chaos. Evil sorceress... | Read more »
Nightgate (Games)
Nightgate 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: *** Launch Sale: 25% OFF for a limited time! *** In the year 2398, after a great war, a network of intelligent computers known as... | Read more »
3 best fantasy football apps to get you...
Last season didn't go the way you wanted it to in fantasy football. You were super happy following your drafts or auctions, convinced you had outsmarted everyone. You were all set to hustle on the waiver wire, work out some sweet trades, and make... | Read more »
Pokemon GO update: Take me to your leade...
The Team Leaders in Pokemon GO have had it pretty easy up until now. They show up when players reach level 5, make their cases for joining their respective teams, and that's pretty much it. Light work, as Floyd Mayweather might say. [Read more] | Read more »
Ruismaker FM (Music)
Ruismaker FM 1.0 Device: iOS Universal Category: Music Price: $4.99, Version: 1.0 (iTunes) Description: Following up on the success of Ruismaker, here's her crazy twin-sister, designed for people who want to design their own... | Read more »
Space Marshals 2 (Games)
Space Marshals 2 1.0.15 Device: iOS iPhone Category: Games Price: $5.99, Version: 1.0.15 (iTunes) Description: The sci-fi wild west adventure in outer space continues with Space Marshals 2. This tactical top-down shooter puts you in... | Read more »
Dungeon Warfare (Games)
Dungeon Warfare 1.0 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0 (iTunes) Description: Dungeon Warfare is a challenging tower defense game where you become a dungeon lord to defend your dungeon against greedy... | Read more »

Price Scanner via

BookBook Releases SurfacePad, BookBook &...
BookBook has released three new covers just for iPad Pro: SurfacePad, BookBook and BookBook Rutledge Edition. BookBook for iPad Pro is a gorgeous leather case reminiscent of a vintage sketchbook.... Read more
Clean Text 1.0 for iOS Reduces Text Cleanup a...
Apimac today announced availability of Clean Text for iOS, a tool for webmasters, graphic designers, developers and magazine editors to reduce text cleanup and editing time, and also for any iPhone... Read more
27-inch iMacs on sale for up to $220 off MSRP
B&H Photo has 27″ Apple iMacs on sale for up to $200 off MSRP including free shipping plus NY sales tax only: - 27″ 3.3GHz iMac 5K: $2099 $200 off MSRP - 27″ 3.2GHz/1TB Fusion iMac 5K: $1899 $100... Read more
Apple refurbished 13-inch MacBook Airs availa...
Apple has Certified Refurbished 2016 and 2015 13″ MacBook Airs now available starting at $849. An Apple one-year warranty is included with each MacBook, and shipping is free: - 2016 13″ 1.6GHz/8GB/... Read more
Apple refurbished iPad mini 2s available for...
Apple is offering Certified Refurbished iPad mini 2s for up to $80 off the cost of new minis. An Apple one-year warranty is included with each model, and shipping is free: - 16GB iPad mini 2 WiFi: $... Read more
Save up to $600 with Apple refurbished Mac Pr...
Apple has Certified Refurbished Mac Pros available for up to $600 off the cost of new models. An Apple one-year warranty is included with each Mac Pro, and shipping is free. The following... Read more
Mac Pros on sale for $200 off MSRP
B&H Photo has Mac Pros on sale for $200 off MSRP. Shipping is free, and B&H charges sales tax in NY only: - 3.7GHz 4-core Mac Pro: $2799, $200 off MSRP - 3.5GHz 6-core Mac Pro: $3799, $200... Read more
Will We See A 10.5″ iPad Pro in 2017? – The ‘...
A MacRumors report, cites a research note from KGI Securities analyst Ming-Chi Kuo, saying a new size iPad model is in the works. According to the highly respected Cho, who has a strong track record... Read more
IOGEAR USB-C Docking Station Transforms Lapto...
IOGEAR has announced the launch of its innovative USB-C Docking Station with Power Delivery which turns USB-C enabled laptops into desktop workstations. The new IOGEAR USB-C Docking Station features... Read more
12-inch Retina MacBooks on sale for up to $10...
Amazon has 2016 12″ Apple Retina MacBooks on sale for $100 off MSRP. Shipping is free: - 12″ 1.1GHz Space Gray Retina MacBook: $1199 $100 off MSRP - 12″ 1.1GHz Silver Retina MacBook: $1224.99 $75 off... Read more

Jobs Board

*Apple* Engineer - Softthink Solutions, Inc....
Job Description:- Proven experience in administering IOS and OSX Apple devices in enterprises - Experience in administering Apple devices in Windows environments Read more
*Apple* Professional Learning Specialist - A...
# Apple Professional Learning Specialist Job Number: 51234243 Portland, Maine, Maine, United States Posted: Aug. 18, 2016 Weekly Hours: 40.00 **Job Summary** The Read more
*Apple* Mobile Master - Best Buy (United Sta...
What does a Best Buy Apple Mobile Master do? At Best Buy, our mission is to leverage the unique talents and passions of our employees to inspire, delight, and enrich Read more
*Apple* Retail - Multiple Positions Akron, O...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Simply Mac *Apple* Specialist- Repair Techn...
…The Technician is a master at working with our customers to diagnose and repair Apple devices in a manner that exceeds the expectations set forth by Apple Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.