Mouse tracking by Lap Cat
How do you call among you the little mouse, the mouse that jumps? Oh, that’s right, we call that one Mighty Mouse. Actually, my cat prefers the keyboard. He must be a hacker at heart. (A hacker and a slicer.)
In the post Single-click renaming in NSTableView, I mentioned that Cocoa gives the appearance of being able to see into the future. Now I’ll describe another example of this phenomenon. Strange things are afoot at the Circle K! Our story begins with a Vienna bug: mouse-clicking in another browser tab didn’t always bring the other tab forward. The bug seemed to occur at random, and that, as you know, is the worst kind of bug. (Though yellow jackets are pretty bad too, I’ve discovered.) So how do we debug de, err, the bug?
Here I come to save the day! Perhaps I’m old school (the Academy), but I find old school methods to be useful, and this looks like the perfect situation for NSLog(). (It’s a little known fact, however, that NS stands for New School.) I’ve uploaded a simple demo application project, TrackingRects, that simulates mouse tracking for Vienna browser tabs with close buttons. The application presents a window containing two larger boxes, or ‘tabs’, each of which contains a smaller box, or ‘close button’. Every box has a mouse-tracking rectangle, or ‘cat’, within its borders, and all of the resulting mouseEntered: and mouseExited: messages are logged.
If you move the mouse in and out of the boxes slowly, then everything works as expected. Weirdness begins to happen, though, if you zip the mouse through the boxes. According to the logs, the mouse has entered the second box before it exited the first box. You can’t be serious! You cannot be serious! Yet logs don’t lie, folks. (Although they do sometimes commit sins of omission.) Apparently, Cocoa likes to send mouseEntered: messages before mouseExited: messages when they’re close enough together. It’s almost as if your mouse were approaching the speed of light, and events that appear in sequence from the mouse’s perspective appear simultaneous from the perspective of the stationary window, because of the principles of special relativity. Wow, you didn’t think you needed to be a rocket scientist to write Cocoa apps, did you?
Moral of the story: Do not rely on the runtime to send event messages to your code in a particular order. And most important, do not do your homework without wearing headphones.
The post is over, thought I’d something more to say.
October 26th, 2006 at 8:45 pm
I Iike Vienna more after reading posts like this.
October 28th, 2006 at 12:20 am
There was a bug in Vienna where mouse-clicking in another browser tab didn’t always bring the other tab forward. The bug seemed to occur at random (worst kind of bug).
I’ve uploaded a simple demo application project, TrackingRects, that simulates mouse tracking for Vienna browser tabs with close buttons. The application presents a window containing two larger boxes (simulating tabs), each of which contains a smaller box (simulating a close button). Every box has a mouse-tracking rectangle within its borders, and all of the resulting mouseEntered: and mouseExited: messages are logged.
If you move the mouse in and out of the boxes slowly, then everything works as expected. Weirdness begins to happen, though, if you zip the mouse through the boxes. According to the logs, the mouse has entered the second box before it exited the first box. Apparently, Cocoa likes to send mouseEntered: messages before mouseExited: messages when they’re close enough together (!).
Bottom Line: Do not rely on the runtime to send event messages to your code in a particular order.
October 28th, 2006 at 10:29 am
I reported this Dec 2005 as radar bug 4375548 at Apple, with a request to at least document this behaviour; case is still open
October 28th, 2006 at 10:47 am
Now the Apple documentation can just link to my blog post!
Strangely, when I used SummaryService to get the post down to one sentence, the sentence was I guess programming is rocket science. Can’t … crack … a smile … wouldn’t be logical, captain.