Solipsism Gradient

Rainer Brockerhoff’s blog

Browsing Posts in Software

Re: What, already?

No comments

gracion wrote:

Happy New Year, Rainer! Very good summing up of the year, which I agree with, except I’m not sure I want to kill .Mac. Here’s why…

Same to you, Paul!

Anyway, it’s not that I want to kill .mac. I’d say that, despite all the good intentions and (I suppose) working APIs and facilities, the actual server infrastructure they use seems to be deficient, and the price is excessive when compared to the benefits. Google has much more resources to throw at that, of course… and for you people living near the actual servers it may even be working well; it never did for me when I tried it out. Mounting an iDisk here means endless waits or a hung Finder.

Regarding syncing and backup, I’d feel much better with that also supported by a local server. Apple should really publish this as a Mac OS X service.

What, already?

No comments

Heh. Seems the year’s over already and I almost didn’t notice.

Looking back, it’s been a busy and surprising year. I traveled more than I’d planned and wrote less. XRay II saw a lot of progress in fits and starts, but my plans to release a public beta this year didn’t work out – mostly because I had underestimated the back-end work necessary to actually save data.

On the Apple front, the year has been busy. No iPhone from Apple. Zune out, Vista out (sort of), AAPL options scandal, Leopard, Mac Pro, the Intel migration has been completed, lots of security flaps, new laptops… it’s a long list, so long I don’t feel like finding all those old links. Looking back, what surprises me most is that Apple doesn’t seem to be as interested in virtualization as I felt they should be.

And of course MacWorld is just a little over a week away. Rumors are already flying fast and furious, of course. Here are some things I believe to be more likely (not that I have any inside knowledge, I hasten to add):

  • New Apple displays, with built-in iSights and microphones.
  • New Mac Pro with 8 cores, probably with a new case design.
  • The transition is over, and people are now sure the Intel Macs are “really Macs”, so new case designs are overdue across the whole line, although in the case of the laptops I’d say that’ll be really hard. Thinner and better/larger screens of course, but there’s only so much you can do with minimalism.
  • Leopard? Perhaps we’ll finally see some UI changes. My tip for the release date is March/April.
  • iTV, no idea in which direction they’ll take that; I watch very little TV. Regarding the name(s), it would make sense to go away from the whole iThing.
  • whateverPhone: I don’t use a cellphone, so the basic idea leaves me cold. Unless Apple breaks the entire paradigm with some sort of VoIP breakthrough, it’s bound to be some sort of weak US-only experiment. Let’s hope they don’t do that. I also see no sense in having music capabilities built-in as a default. Opening it up to developers in a big way would be excellent, and the recent rumors of a stripped-down, embedded Mac OS X dovetail with that.
  • .mac is dead. It’s never worked well (or at all) outside the US, as far as I know. It’s an expensive embarrassment. Apple could close it outright, sell it to Google, or allow people to operate their own sync servers.

Flipr out

No comments

Searching for some cool eye candy to add to my applications, I thought of having the main window flip around to present the preferences window – an effect pioneered by Dashboard widgets. Not finding a ready-made solution I set out to do it myself, and learn how to use CoreImage from Cocoa.

So, here’s some new source code: a category on NSWindow to flip from some window to another window. Please read the “ReadMe” file for details and caveats. The code should work on any PowerPC Macs with AltiVec, and any Intel Macs.

That said, it’s not as fast as I thought it would be, and I don’t want to spend more time on it right now. I’ll be looking into Quartz Composer to do something similar, although the upcoming CoreAnimation (for Leopard) will probably make this completely obsolete very shortly.

Re: Update: XRay

No comments

Rainer Brockerhoff wrote:

…Imagine my surprise when I learned that Peter had just published the complete Hex Fiend source code, and also started up a Wiki to explain details…

That said, I haven’t had time to look at details of his data backend yet, but that too looks like it will save me at least a month of tinkering.

Well, I’ve now had a little time to look at the Hex Fiend code.

As I expected, it builds a tree of referenced/changed byte ranges for an edited file. There’s a generic “ByteSlice” class with concrete subclasses that represent either a range of bytes inside a file or a range of bytes in memory – the latter would be the result of an editing operation like typing or pasting in stuff. That much I’m already doing myself, albeit with different names.

The interesting part comes when an edited file is saved. Hex Fiend goes to great lengths in optimizing writing time, allocated RAM, and disk space; it uses threaded AVL trees and lots of neuron grease, and while I understood very generally what’s supposed to be going on, the details are extremely daunting. My hat’s off to the wizard. And he spent similar care on optimized searching, too.

Now, just lifting all that code and plopping it into XRay II just wouldn’t be cost-effective. Yes, the result is that you can open a 240GB file on a 250GB disk, swap huge chunks of it around, and insert random bytes in the middle, and save it with no problem. Do I see this situation arising frequently for XRay II users? Frankly, no. Remember, the idea is to do structured editing of file contents, not necessarily pure hex editing… and Hex Fiend is already terrific at this (not to mention, free). I see the hex editing panels in XRay II more suited to editing small amounts of data and as a convenience to view raw file contents without necessarily changing them.

So, falling back on the old method of saving an edited file to a temporary file, then swapping it with the original if creation succeeded, means that complexity will go way down at the expense of speed (noticeable only for really huge files) and of the necessity of extra free space (same).

A second problem is that, for Hex Fiend, a file is just a sequence of bytes – no structure. For me, on the contrary, changing a byte in one place – meaning editing a representation of (say) an ID3 tag in a music file, or a QuickTime atom in a movie file – will usually mean that elsewhere in the file one (or even several) count or length fields will also have to change, preserving the file’s integrity. So my data representation tree also needs to reflect a particular file’s format as decoded by a plugin – and there may be several plugins seeing the file in different ways – and the nodes need to be more intelligent, notifying each other when necessary.

Still, seeing the Hex Fiend code has given me assurance that I can do it myself, so that’s good… icon_biggrin.gif

Milking Mice

No comments

So, there I was in my trusty BBEdit (thanks Rich!) twiddling HTML code for a friend’s website, trying to get stuff aligned “just so”, checking out the CSS, cleaning up some redundant markup – and of course reloading the browser after every change to be absolutely sure it worked. My friend, who knows how to operate her Mac but is otherwise non-technical, watched this with astonishment… after we were finished (took most of an evening) she exclaimed, in German, “Das ist ja zum Mäusemelken!”

I burst out laughing at this colloquial expression I hadn’t encountered before, and which literally means “that’s for milking mice!”, but actually is used in the sense of “that’s extremely exasperating!”. Or so Google tells me. However, in the sense of twiddling with HTML code – or Objective-C code for that matter – it struck me that it can be taken literally. To quote Tom Digby’s “Little Tiny Eyes” (found via Tim Bray):

“OH YOU NEED LITTLE TEENY EYES FOR READING LITTLE TEENY PRINT

LIKE YOU NEED LITTLE TEENY HANDS FOR MILKING MICE.”

Yep, you have to position those little teeny hands just so and be extremely patient because it’ll take a long time to do it right and get enough… and it takes a very peculiar and determined kind of person to sit there N hours per day, day in and day out, just twiddling away at the little bits to get everything running “just so”.

And that is why my main page has the subtitle “finely crafted software for the Macintosh”. Hm. Should I change this to “Digital Mice Milking” or something? But I suppose that, just because I put this title on this post, that Google will already put me somewhere on its mousemilking results, forever after confusing hapless NIH researchers. But then, that’s the price of fame…

Update: XRay

No comments

As expected, I’ve worked a lot on XRay II during the trip. I’d hoped to get the raw data updating backend working, but unfortunately debugging the plugin interface took much more time than I had anticipated. In particular, I ran into edge cases on my automatic view resizing algorithms and had to refactor them completely; it turned out that I had 3 different cases – for NSTextFields, for my outline views, and for plugin views – which were fighting each other and thus had to be folded into a single model. Anyway, the new scheme seems conceptually sound and the only thing missing are some optimizations.

To test all this out I started work on a QuickTime plugin. Currently this has a movie preview pane and a QuickTime atoms pane. The preview pane was actually working well when we started out on the trip but it turned out to be surprisingly hard to adapt to the view resizing scheme, so I’ll have to redo it. I’m using Tiger’s new QTMovie view which does a lot of work for you, but at some point it’s unavoidable to dip into the old Carbon QuickTime API which is, to put it mildly, a confusing patchwork.

No doubt there are sound historical reasons for this, but it’s a huge pain to get it all working in a modern Cocoa environment. For instance, the movie inside a QTMovie view doesn’t necessarily obey Cocoa’s clipping rules while it is playing – especially if it’s a QTVR panorama. QTVRs also seem to override Cocoa’s cursors even if the view itself is hidden or clipped out.

The second pane does a hierarchical display of QuickTime atoms. There’s a huge and confusingly documented roster of possible QuickTime atoms and they may be nested in often unintuitive ways. So far, I’ve been just using them to debug my nested container views and the autoresizing scheme, but it’s clear that this will probably be an extreme test case for both; other plugins won’t stress these aspects so much.

With all this, the data updating scheme took a back seat. Briefly, XRay II plugins will interact with the file system over an abstraction class called XRayItem. An item can represent an actual file system item, the entire contents of one such an item’s data or resource forks, or specific subparts of those. The idea is to have plugins chop XRayItems up into smaller pieces and pass them to other plugins to format and display them. Ultimately, once a data portion is changed by some editing action by the user the changed data are cached and the changes are passed upward the chain so other plugins can update their own representations accordingly. Then, when the changes are saved, they have to be collected and written out into a reasonably efficient manner.

Turns out this is not as easy as it sounds. Starting with just the default plugins that show the hex view of a file’s data fork, the user might want to open a 20GB file, select half of it, cut it to the clipboard, past it back at the end of the file (or even another file), go back to the middle and change a single byte, then do a search/replace loop over the result. Since, on Tiger, a typical Cocoa program can allocate just a little over 2GB of RAM (and not necessarily in a single chunk), this becomes a non-trivial memory management problem.

Of course, for the vast majority of files up to a certain limit – let’s say up to 128MB or so – keeping all that in RAM and changing it there would be the simplest and not-to-slow solution, and I’ll certainly have a fallback implementation for that. And if this were a Leopard-only app with a 64-bit version, this limit could be pushed a lot higher – but it has to run on Tiger and on 32-bit systems too.

So I was putting this off while tinkering with the other parts of the app, and seriously considering asking Peter Ammon for more hints, as I knew he’d solved the problem in his excellent HexFiend hex editor. Imagine my surprise when I learned that Peter had just published the complete HexFiend source code, and also started up a Wiki to explain details. Thanks a lot, Peter. Every Cocoa developer should download this gem, there’s lots of cool stuff inside from a Cocoa team insider; I’ve already learned how to filter out all fixed-width fonts, for instance.

That said, I haven’t had time to look at details of his data backend yet, but that too looks like it will save me at least a month of tinkering.

Re: Text editing…

No comments

Yet Another interim progress report on XRay II.

Turns out some of my problems with the hex editor were due to overuse of the idea to have my scrollview’s delegate do everything (including standing in for the First Responder). So I changed back to a simpler model. I now have a single view inside my scroll view as the delegate, and it stays in place – it just checks the scrollbar’s status to decide what to draw.

As this subview is declared as NSView<NSTextInput> – meaning it’s a plain subclass of NSView that obeys the NSTextInput protocol – it’s also a descendant of NSResponder, and now stuff started “just working”. Seems obvious in retrospect, of course. There’s lots of details about implementing that protocol, but it’s mostly working now; I’m still not doing any actual editing, but that’s the top item on my list of things to do next.

Several other issues are being worked on in the meantime. Many things are more complex than I anticipated, but I believe the final result will be worthwhile. The actual plugin interface is still mutating from day to day, mostly because the actual usage patterns are hard to anticipate. I have two plugins partially working: File Metadata and File Forks (which use the basic hex editor to do its work).

I’m now making a separate version of the main XRay II application to be used as the plugin developer base. This will be a stripped-down version of the application: it’ll run only the two basic plugins and a third one, the one being developed. It will also have some debugging infrastructure in place.

Next, I’ll use this to start up projects for at least two more, perhaps more, plugins of different types, both reusing basic UI elements from the main application. Hopefully this will give me enough variations to publish a rich but robust plugin interface. I envision stopping development on the main application as soon as possible – perhaps even this year, if all goes well – and doing all the rest inside plugins.

Text editing…

No comments

Autoresizing NSTextFields are now working quite well, except in one instance – when there are several of them stacked and the window is resized several times very rapidly. I’ve left this alone for now while tackling another problem: text editing. Let me explain this a little.

One of my basic UI elements is a fast hex editor view. Here’s what it looks like at present:

Three columns, hex displacement at the left, hex characters in the center, MacOSRoman (or any other encoding) to the right. All in a scrolling view. That’s where things began to get strange. For normal Cocoa use, you’d normally define an NSTextView inside an NSScrollView. The three columns might be done by NSTextBlocks, as this will be Tiger-only. Or three different NSTextContainers, each one referencing an aspect of the same NSTextStorage…

The main stumbling point here is, I want to be able to edit very large files with no performance penalty. Files tens of gigabytes in size or even larger. All the standard Cocoa text objects above are out; they use 32-bit offsets and ranges for text sizes and selections, meaning things are limited to 4GB (or even 2GB in some cases). Also, NSTextView becomes slow as molasses well before text sizes reach those magnitudes, as the entire text needs to be laid out first to determine line breaks. Also, RAM requirements to generate the hex interpretation go up – remember a standard Mac OS X app can allocate just a little over 2GB of RAM. Finally, NSScrollView uses floats to track the scroll thumb position, meaning that scroll tracking becomes imprecise when you’re trying to track millions of lines.

Well, my fate apparently is to recode most of the NeXT-era UI widgets anyway – see RBSplitView. I tackled the scroller problem first, as I needed it for the file browser anyway, and soon had a special scroll view that tracked scrolling positions with unsigned 64-bit displacements – large enough for the largest file supported by Mac OS X – and faster and simpler than the standard one. It basically consists of the vertical NSScroller and the empty (document) space to its left; no intervening NSClipView. Any subviews are relocated by the offset when the scroller changes and drawing is optimized to the visible portion.

I also put in the option to have the view’s delegate redraw the visible portion directly – this was the idea I had to optimize the hex editor. Indeed, drawing is very fast; I have my own cached CoreGraphics bitmaps of the characters, and blit them to the visible portion of the sscroll view. And only the necessary part of the displayed file needs to be accessed, thanks to mapping only that part to memory with mmap(). And putting in editing later would be easy once the display portion is finished…

Famous last words. Turns out that the Cocoa text system is rather more complex than I expected – the standard NSTextView/NSTextField objects hide that very successfully from the “normal” developer. After several days of reading the very terse docs, and trying to find out which methods are called where, I’m finally at a point where the normal text input methods are working. However, I still can’t figure out how the standard copy/cut/paste menu items are enabled, and the whole process is still too clunky for wider use.

Stay tuned for developments…

Photos licensed by Creative Commons license. Unless otherwise noted, content © 2002-2024 by Rainer Brockerhoff. Iravan child theme by Rainer Brockerhoff, based on Arjuna-X, a WordPress Theme by SRS Solutions. jQuery UI based on Aristo.