Sunday, July 15, 2007

Mac and me

I'm sitting at the Oakland airport, waiting to take off for my semi-annual trek to Boston. For the first time in years, I'm not accompanied by my trusty Dell Windows laptop. It chose Friday the 13th to sound its death knell, first stopped running a few programs, then slowed down, then went crazy, finally turned blue and died.

Rather than travel laptopless, I brought along my Mac PowerBook, on which I am now typing. It's not a bad little machine. Good battery life. I hope I can get it set up to do e-mail from the hotel room. Hope I can get by without FrontPage and Visual Studio and Outlook and all my old friends.

I've been using Macs on and off for some time now, and I can't quite see what all those Mac fanatics are so wild about. I can't seem to get comfortable with it. It's partly the fact that it's a laptop, with this crowded little keyboard, but it's more to do with the way the software works, and the sort of "unix cowboy" mindset it seems to want. For me, Windows is a comfy old shoe, Mac is more of a pointy boot.

Gripes

For starters, there's the desktop, with the menu along the top that changes depending on the active program. You're working on some document, pouring concentration into it, you want to enlarge the window, so you reach down to grab the resizing corner. Miss it by a fraction of an inch, and poink! you're in some other program, the menu has changed, some other window pops up in your face. Concentration fades while you root around getting back to where you were.

The delete key deletes the previous character, not the next one. Where's backspace? I find I'm always forgetting this and having to hit cmd-Z (not easy, the way they've placed the cmd key) then cursor forward a few characters so I can delete backwards through them. So maybe I'm used to Windows, but still, I shouldn't have to work to get used to stuff like this.

There's this cutesy dock bar at the bottom of the screen, full of icons too fancy for the average programmer to make. Hover over one of them and it pops up like a cartoon genie. Kind of cute I suppose. But here's the problem: a window on the screen can go behind the dock bar. It's semi-transparent, so you can see your window sitting there beneath it, but then try grabbing the corner to resize the window (for some reason it can only be done at the lower right corner) -- you can't do it, you'll hit the dock bar, a genie will pop up and all of a sudden you're in OmniGraffle or some such thing.

Then there's the development environment, Xcode. The more I work with it, the more I appreciate Microsoft Visual Studio. Xcode has a bunch of different environments, one for building, one for developing, debugging, etc. You're working in some window of code, pouring concentration, etc., and you need to look something up in some other file. To find the file, you typically bring up a tree control (for some reason there are two of these, similar but not alike), which switches you into a different environment. Your file is gone, you have to root around to get back to it. If you're working on several files, they don't tile or stack or show up as tabs, instead there's this little chooser which always seems to have a long list of files in random order. It's like instead of having a few sheets of paper out on your desk where you can look at them, Xcode insists on putting them in one pile and making you look through a Rolodex to find the one you want.

And then there's the vaunted Apple hardware. I didn't have this machine a month before one of the key caps broke off. So if I want to type a 2 or @, I have to press this little rubble nipple instead of a key. I made a lame attempt to glue the key back on one time, didn't work. A month later, the power adapter fell apart, and is now being held together with a rubber band.

I could go on, and probably will. Who knows, maybe after a week in Boston with this thing I'll start to like it.

Friday, July 13, 2007

Smooth Scrolling

Here's another thing that keeps developers employed: rising expectations. People are surrounded by XBoxes and Pixar movies and iPhones, so they've come to expect lots of dazzle for low prices. This is tough on the lone guy trying to compete with a computer in a garage. Getting rid of every little flash or unpainted pixel on the screen is a big chore, and game-level animation is tricky.

My idol Joel Spolsky recently wrote that software development is a "game of inches." You just keep inching along, ironing out the next little wrinkle, and eventually your program will be as cool and popular as Joel's. If it does animation, you have to keep tweaking to make it smoother and more attractive.

I recently inched. My program has always had this annoying glitch in one aspect of the animation. One afternoon this week I came up with a nice solution, so I will now go into Technical Blog Mode and tell you all about it.

The Problem

An object is moving across a background on the screen. When it gets near the edge, you don't want it to move off and become invisible, you want the background to automatically scroll so the object stays in view. Call it "auto-follow."

It works like this. If the object is about to move out of view -- about to cross an invisible boundary about an inch from the edge -- then you need to shift the background enough to keep it in bounds. Say it's moving east, and the next move will carry it 10 pixels beyond the right boundary: what you do is scroll the background 10 pixels to the left, then redraw the object.

The first time I tried this, it looked ok, but kind of jittery and nervous. The object (ok, it's a train) is moving with arbitrary speed and direction, so maybe on one tick it needs to scroll by 10, then by 4, then 15, etc. Shifting the whole screen by a different amount each time looks unsmooth.

I solved this with a little governor mechanism. It said: if you need to scroll by any amount up to 20 pixels, scroll by 1 instead. The train moves beyond the boundary, but the scrolling is smooth and usually manages to catch up after a while. I fiddled with the parameters of this until it looked pretty good at most speeds, and it's been in effect since 1.0.

But there is still jittering, due to a more fundamental problem. Consult the pictures. In the top frame, the train is at the edge, about to cross the boundary (red line). Call ScrollWindow, and you get what's shown in the next frame: the window contents have shifted to the left, leaving an unpainted stripe along the right edge. This stripe gets repainted, and you end up with what's in the bottom frame.

The problem is that when you scroll the window, it moves the train image along with it. So the train appears to hit the boundary, then jump backwards a little bit as the window is scrolling, then jump forward again as it's painted in the new position. The background is scrolling smoothly along, but the train is doing the rhumba against the edge of the screen.

The Better Way
This is one of those problems that took a long time because I kept looking for a built-in solution. Figured I was calling the scroll routine wrong or something. I finally figured out that the built-in solutions are made for scrolling text, and for doing animation I was on my own.

What has to happen is obvious, right? We need to go straight from the top frame to the bottom, without letting the user see the one in between. Make it look like both the background and the train move in a single update.

To do this I had to duplicate some code from various layers of MFC, so it would do all the same positioning of scrollbars, moving of view origin, etc., down to the point where it called the system ScrollWindow routine. This is the routine that actually moves the pixels on the screen and gives the middle frame. So I just skipped it. Then moved the train, then repainted the entire window, and voila, it looked like everything moved at once.

Should've done this years ago.

Monday, July 9, 2007

The Distance from .39 to .4


Say hello to my new friend, a relic from my son's closet.

Seductive isn't she, with that curvy bod and the see-through top? I'm told the color is "sage," which looks like teal to me, but maybe that's my Windows bias showing.

Sagey and I are on a quest to reach out to those Mac users who haven't yet upgraded to OS X 10.4. They write and tell me why: my machine has an old hard drive, it really belongs to my cousin, I lost my last hundred at the track, blah blah. It's what keeps us developers employed -- the operating systems keep evolving, the customers don't.

A year ago, standing at the base of this mountain of a project, I couldn't worry about such details. I wanted something to run on a Mac, any Mac. Nine months later, when it ran on mine, I wrote the system requirements ("just like mine") and shipped it.

(In case you're wondering about the flood of orders which surely followed this historic release, let's put it this way: the TP Mac Users Group meeting could easily be held in my kitchen, with plenty of room left for chips and beer.)

Right away I started hearing from 10.39 users, wondering whether they might try the program. I didn't know what to tell them. I figured it might run. If this were Windows, and the operating system version changed by 0.01, everything would still work, it would just have more security warnings.

I didn't have a 10.3 machine, and the only people I knew did were these guys writing in. So I pulled my usual trick: recruited a couple of them to do some testing. It's my low-cost outsourcing program. In exchange for a free copy of the software, I can often get a savvy user to do a couple weeks' worth of useful experiments to help track down a problem. Lately I’m getting a lot of great help from Kent Dristle.

So I sent out the first version to these guys and said give it a try. Answer: program doesn't start. On Windows, this would usually be accompanied by an alert about some missing dll -- if you could find it and put it in the right place, the problem would go away. On the Mac, it just honked and gave no clue.

That’s when I discovered the Magic Switch -- an option in the build settings called “compatibility,” which let me choose 10.3. So I just flip this switch, rebuild, and it will run? Cool. But after another round trip to the testers, it was still no go.

Turns out there is a much bigger hammer in the build settings: a choice to link with the 10.39 SDK. This is like setting the clock back – flip this switch, build, and it complains about functions that haven’t been invented yet. This turned up at least a dozen calls to routines where, sure enough, the fine print said “10.4 only.” I hastily commented out some of these and sent out another version, and this time, success! Sort of! “Starts but crashes immediately” they reported.
Evidently the way the compatibility switch works is: if it comes across a function not supported in 10.3, it doesn’t complain or crash, it just does nothing. Where you were making a call and expecting an answer, you get zero, and usually a crash. So further patching was necessary, and on the next round-trip we were at “Runs but sucks.”

Enter Sagey. With a 10.39 development environment it’s easy to find out about problems like: the Inspector doesn’t come up (because it included a 10.4 gadget called a DatePicker); it doesn’t print (our call to the print routine was 10.4 only; the compatibility substitute did nothing); train movement is jerky (every time the train was redrawn, a jpg image was being slowly decoded).

So all this is now getting ironed out, and I hope to post an upgrade in the next few days. Should make life easier for both our 10.39 users.

Tuesday, July 3, 2007

Delivering the Goods

Standing here on the brink of releasing a new product, I scan the terrain ahead. Adding one product seems like no big deal, but it pretty much doubles the complexity of an already involved process.

At the moment we have a total of 8 products (where product is defined as "something with a price") -- 9 if you count the free demo version. The program has two levels (call them Standard and Pro), each with one of two sets of data files (Partial and Full) -- so four main products SP, SF, PP, and PF, plus three add-on sets of data files and an upgrader to go from S to P. All told, a whopper of a catalogue.

To deliver these 9 products, we have a total of 7 different installers (where installer is defined as "something you download or get on CD") built around a grand total of 1 (one, count it) executable. The same program acts as demo, S, or P, depending on what license code you enter.

Adding the screensaver causes the number of products to skyrocket. You might want to purchase SS by itself, with or without the full set of data files, or if you buy any other product you might want to toss in the screensaver (forget "toss in" -- it'll be $10) so 4 choices become 8 and the product line leaps from 9 to 15. The increase in paperwork alone will be staggering.

So here's my plan for making this manageable. First, you might be amazed to know that the very same file can act as either program or screen saver, depending on where you put it and how smart it is (more on this in my CodeGuru article). Second, since the license can tell the program to behave in any of several ways, we can still get away with just one executable -- now installed in two different locations, with one set of data files, and a detailed license code telling what it can and can't do.

We won't need any more installers. Every one can go ahead and put the screensaver in place, since it won't work unless you have the right license. Some people might be annoyed to see it in the screensaver list if it doesn't run, but if they gripe I'll tell them how to delete it.

So many things to think about with this big new catalog! I'd better order more paper clips.

Monday, July 2, 2007

Screen Saver Adventures

Well, so much for the Great Mac Conversion Saga. I was determined to write a chapter a day, then two weeks went by and nothing showed up. I got distracted. I'll get back to it someday.

What distracted me was another project a lot more fun than the dang Mac. Something I've been thinking about for a year or two, working on for the last couple of weeks, and which is now in beta testing, almost ready to add to my little product line. Steve Jobs asked me to hold off putting it out there so it won't distract from the iPhone release, but I can't wait much longer.

Announcing the TrainPlayer Screen Saver, a pointless device designed to extract money from model railroaders with nothing better to do than stare at idle screens. I can already see the dollars pouring in, tens upon tens of them! Kids will get double birthday bonuses next year!

I've been putting this project off, mostly because I thought it was going to be a huge job, total rewrite of the program, etc. But I came up with a rather simple and elegant approach, with which I am so pleased that I'm submitting an article to CodeGuru about it. It takes months to get these things published, but here's the preview: MFC App to Screen Saver- the Easy Way. Sure to be a classic.

This approach gave me a basic screen saver in about a day, after which I spent two weeks working on "choreography." You can't just fill up the user's screen with some boring static view, it has to dance and be interesting to watch. So there is this scene manager, with three timers going, which causes the scene to zoom in and out periodically, does random changes of the background color, and attempts to keep everything moving smoothly.

Most screen savers disappear at the slightest provocation -- a touch of a key or swipe of the mouse. Turns out this is not a rigid law. While debugging, I found it handy to permit keystrokes to do useful things, and eventually it dawned on me that the user might want the same capability. So this is not your average screen saver. If the train is going off in some loser direction, you can hit a key to back up and throw a switch and go some other way. We push the frontiers, don't we? The Screen Saver: Not Just For Staring Any More.

But enough of this silly blogging. I have bugs to fix.