Archive for the ‘Personal’ Category

Working without a nib, Part 2: Also Also Wik

Monday, June 4th, 2007

I apologize for the fault in the subtitle. Those responsible have been sacked. What I intended to say was that I’ve discovered the Holy Grail of Cocoa hacks: how to create a functional Cocoa application without any nib. In Part 1 of this series, I suggested that you needed a nib for the main menu of the app; some would even argue that having a nib is the essence of a Cocoa app. It turns out that I was wrong, and some (they, the unspecified straw persons) were wrong too. I apologize for any faults in my previous post. Those responsible would be sacked, but those responsible for sacking have just been sacked.

As you may recall if you have a photographic memory or nothing better to do, the main problem with getting rid of nibs is setting the application menu. I had been using a minimal nib as a workaround, but now I have a reliable, though undocumented, solution to the problem. I came upon the solution by using gdb and JJApp (along with a herring) to override initWithCoder: while the main menu is loaded from a nib. The class NSMenu has a private ivar _name, declared in /System/Library/Frameworks/AppKit.framework/Headers/NSMenu.h, that is usually nil, but a few menus — including the application menu — have a string value for the ivar. Although there are no public accessors, we can set the value anyway through the magic of key-value coding. For example, I called setValue:@"NSMainMenu" forKey:@"name" on my main menu and setValue:@"NSAppleMenu" forKey:@"name" on my application menu. This must be done before the return of -[NSApplication finishLaunching], otherwise it will have no effect. I find applicationWillFinishLaunching: to be a good place to set your main menu.

Another caveat is that the old deleting-the-nib trick doesn’t work at all if you change NSPrincipalClass in Info.plist. When I set it to my NSApplication subclass, the app refuses to launch, complaining, No NSMainNibFile specified in info dictionary, exiting. Strangely, it works fine if I leave NSPrincipalClass alone and call [[JJApplication class] poseAsClass:[NSApplication class]] in main.m. A special treat is that Cocoa automatically adds the Special Characters item to the Edit menu at runtime. Thanks, Cocoa! You can see all of this yourself by downloading my sample Xcode project, Nibless. If you use my code in your app, I may sue you, or I may kiss you. In either case, it’s a risk you’ll have to take. (It!)

Despite the fact that my solution is for the most part unsupported by official API (consult the book of armaments!), there’s good reason to think that it’s stable and should survive Leopard at least. Apple is unlikely to remove an ivar from such an important class as NSMenu. More important, the value of the ivar seems to be the way that archived menus indicate their function to Cocoa and to Interface Builder, as reflected by the “Special Menus” setting in the Inspector. Try opening keyedobjects.nib with BBEdit, and you’ll see that the file is just a plist containing definitions of the objects in the nib.

In Part 5 of this series — sorry, Part 3 — I’ll investigate the cause of the log message Could not connect the action buttonPressed: to target of class NSApplication when launching without a nib. I’ll also attempt to populate the Open Recent menu. The Clear Menu item seems to work, but for some reason I can’t get items to appear in the menu. So, um, anything that you could do to help would be very helpful.

I’d like to end this post on a personal note. Many of my legions of fans have sent emails asking for more information about me: birth date, hobbies, pet peeves, dress size, etc. I prefer not to start a cult of personality, but I’ve decided that you, the heroes, deserve something. Thus, I’m going to share one particularly juicy tidbit. My favorite color is … blue. No, yellooooooooow!

Selectors and performance anxiety

Sunday, March 25th, 2007

As I sit on my front porch looking at the 73° temperature (K, since I live on Neptune) in the weather widget on my new MacBook Pro, I can’t help but think that life is good. Yet there’s a nagging voice in the back of my head, reminding me of unresolved issues. Wait, that’s the cat wanting to come outside. In addition, I hear the echoes of Jim Kerr. Let’s forget about them, though, and talk about -[NSObject performSelector:withObject:afterDelay:]. This has absolutely nothing to do with my previous post, honest. You can trust me, because we Neptunians (Neptunites? Neptuners?) cannot lie. We’ve been known to exaggerate, but only once every billion years or so.

The question on all of our minds, at least those of us not suffering from March Madness (to be followed no doubt by April Antisociality and May Melancholy), is what happens when you call performSelector:withObject:afterDelay: with a delay of (NSTimeInterval)0.0 during application launch. It turns out that you can call this successfully pretty much anytime, even during -[NSApplication init], in which case the currentRunLoop will be created immediately rather than during -[NSApplication setServicesMenu:]. It’s also safe to call this as late as during the delegate method applicationDidFinishLaunching:. Regardless of when you call performSelector:, the selector will be performed during -[NSApplication nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantFuture] inMode:kCFRunLoopDefaultMode dequeue:YES] — not the first one, which returns an NSApplicationActivatedEventType, but the one after that. The second one returns an event of type NSFlagsChanged, but I’m not sure whether that matters.

If you call performSelector: multiple times during launch, the selectors will be performed consecutively, during the very same nextEventMatchingMask:, in the order in which they were set up to be performed. Everything seems to happen before any user events — keyboard, mouse, interface licking — are processed. Thus, my conclusion is that -[NSObject performSelector:withObject:afterDelay:0.0] is a safe and effective way of scheduling methods to be performed after application launch but before the user starts wrecking stuff and wreaking havoc. Of course, I also believed that beer was a safe and effective antiseptic, so take my conclusion with a grain of salt … just not in your wound.

Remember, Jim, ice cream is a dish best served cold.

Favorite Feeds updated

Sunday, February 11th, 2007

I’ve updated my list of Favorite Feeds, which is available from the Downloads category in the sidebar of my blog’s front page. It’s in .opml format for easy import into Vienna and other feed readers. The list includes a rather large collection of Cocoa developer blogs, if you’re interested in that kind of thing, and I assume that you are, because you can’t be here just for the jokes.

Speaking of Cocoa developer blogs, I do have a backlog of content that I plan to publish. Really. I’ve confronted a number of coding issues over the past few months that nearly (you be the judge) drove me insane, so I feel an obligation to write about them in order to preserve, or at least not worsen, your mental health. Stay tuned! Don’t take me off your speed dial.

Now back to our regularly scheduled static…

WordPress Bug Fix!

Saturday, January 20th, 2007

This is the first post in what I hope is a series, which I’ll call “WordPress Bug Fix Near Saturday”. And while I’m naming things, I’ll call this first post “Episode IV: A New Hope” (to be followed, no doubt, by “Episode V: All Hope Dashed”). I’m very happy to report that the ETag parsing bug has been fixed in WordPress 2.0.7. Thus, if you’re running WordPress 2.0.7 on your site, you no longer have to comment out the following line in the file wp-includes/classes.php:

@header("ETag: $wp_etag");

My logs confirm that WordPress is now correctly parsing its own ETags and sending out HTTP 200 and 304 responses as appropriate. The Penultimate Warrior is victorious and undefeated! Note, however, that none of the bugs that I reported before the Warrior started Running Wild® (cp. Going Wild®) have been fixed yet.

Speaking of my web site logs, they contain a list of phrases that were used to find my site from internet search engines. I’d like to share a few of them that have caught my eye:

  1. instructions+for+using+the+thighmaster

    Squeeze, release, repeat. You’re welcome.

  2. how+do+u+declare+a+pointer+to+an+array+of+pointers+to+int%3f%3f+in+c+language

    int * (* ptr)[];

  3. talk+to+cat+software

    That doesn’t exist, Dr. Doolittle. Try meowing.

  4. cat+lederhosen

    I’ve given your IP to the SPCA.

  5. betamax+the+sausage+and+the+mouse

    These aren’t the droids we’re looking for.

  6. what+does+ns+stand+for+i+cocoa

    NeXTSTEP. Next!

  7. circle+k+employee+uniforms

    I’m so very sorry, dude.

  8. if+jeff+s+usual+is+a+hint+for+a+password+what+is+the+password

    Stop trying to hack into my account, you scoundrel!

Leopard Tech Talk: Postlude

Thursday, December 14th, 2006

If you think that America is a free country, try driving through Illinois. Their state motto is Give us all of your spare change. As I mentioned before, one of the Mac OS X Leopard Tech Talks was held in Chicago yesterday. (Except that it wasn’t yesterday when I mentioned it before.) I was there, and I had a good time. As you would expect, security was tight: I was asked for my name before receiving a name tag. Apple was kind enough to provide food and drink for the free event, which was much appreciated, though the NDA prevents me from disclosing the items on the menu. I will, however, reveal the latest secret Leopard feature. I can confirm that seeded builds now include a Spotlight-searchable C++ GUI Programming Guide. Thanks, PC guy!

I believe that I can also reveal, since I discovered this information myself by testing, that Vienna is Leopard-ready. Or at least, nothing appeared broken when I played with it for 5 minutes. Yay!

I met a number of people at the event, including fellow blogger Geoffrey Schmit of Sugar Maple Software. The biggest celebrity was Sal Soghoian, AppleScript product manager for Apple. Indeed, he was so famous that he wasn’t required to wear the standard Apple employee uniform, or the 15 pieces of flair. To their credit, the ‘software evangelists’ who gave the tech talks were open and honest. They answered my questions, and they also convinced me to shave my head and dance with an iPod at airports. I would like to thank them, as well as Apple for bringing the show on the road to a location near me.

All I can really say about the content of the talks is that Leopard has a lot of cool stuff for developers. I’m tempted now to get an ADC Select Membership, so that I can receive seeds. (In case you’re wondering, Leopard seeds are not distributed to the attendees of Leopard Tech Talks.) Perhaps that was their insidious purpose. Anyway, I would recommend attending if there’s a Leopard Tech Talk in your area. Amen!

Leopard Tech Talk: See you in Chicago

Friday, December 1st, 2006

I’ve received a confirmation email from ADC that I can attend the Leopard Tech Talk in Chicago on December 13. Thanks, Apple! I’ll try to ensure that Vienna is Leopard-ready.

If you’d like to meet me there, let me know. I should be conspicuous as the only poor soul without a laptop.

CSS tips for HTML

Thursday, November 9th, 2006

I apologize for the absence of posts recently. I’m not dead! I just thought I’d go for a walk. I was feeling the pressure to be funny constantly, so I’ve contracted with Bobcat Goldthwait to ghostwrite my blog posts for me. Umm, I-I-Arrgh, I want a yacht!

During the hiatus, I’ve also been redesigning my web site. Superficially it looks similar, but under the hood it’s now almost entirely hand-coded (with Smultron). The only iWeb-generated code I kept was the JavaScript photo slide show. The benefits of the redesign are that the pages should load faster, and it’ll be easier for me to update the content, as I just did by adding a link to Mac OS Forge, which has finally emerged from its beauty sleep.

In honor of our new site styles, the subject of this post will be CSS. Sorry, folks, one cannot live on Cocoa alone! One also requires marshmallows, and Fritos. You may have heard of collapsing margins, which occurs in a number of contexts, for example, on election day. It also occurs when the bottom margin of a block-level element on a web page adjoins the top margin of another block-level element. The two margins collapse, and the length of the displayed margin becomes the length of the larger of the two adjoining margins. This can be useful, because typically you want a minimum margin around a paragraph of text, and you want a different minimum margin around a heading, but you don’t want a huge gap between the heading and the first paragraph. (Unless you’re trying to turn 8 pages of actual writing into a 15-page term paper. I know who you are, slackers! I was a teacher. Your grade will reflect your ef-fort.)

What you may not realize is that collapsing margins also occurs when the top margin of a block adjoins the top margin of its parent block. If you load the following HTML in a browser, such as Safari or Camino, you’ll see a purple box at the top of the window.


<html lang="en-US">
<head>
<title>Collapsing Margins</title>
<style type="text/css">
body {
	background-color: #000000;
	margin: 0;
	color: #cccccc;
}
#all_content {
	background-color: #590079;
	margin-top: 0;
	margin-bottom: 0;
	margin-left: auto;
	margin-right: auto;
	width: 40em;
	height: 40em;
}
p {
	margin-top: 1em;
	margin-bottom: 1em;
}
</style>
</head>
<body>
<div id="all_content">
</div>
</body>
</html>

This is to be expected, because body and all_content both have top margins of 0. However, if you add a paragraph, <p>This is a paragraph.<p>, inside the element all_content, something unexpected happens. Instead of the purple box at the top of the window with the paragraph spaced from the top of the box, you see the purple box spaced from the top of the window with the paragraph at the very top of the box.

The margins of the paragraph are supposed to be calculated relative to its containing block, which in this case is the element all_content, so you would expect that the margin should appear between the paragraph and the box rather than between the box and the top of the window. The reason the opposite occurs is that even though the box has a top margin of 0, the top margin of the box and the top margin of the paragraph are technically adjoining, which means the margins collapse, and the one true margin becomes the larger of the two top margins. Since margins are transparent, the black background shows through.

The CSS specifications for collapsing margins are, to put it frankly, idiotic. Or to put it more tactfully, they’re insane. Who in the world wide web would want the top margins of parent and child blocks to collapse? I gave the paragraph a non-zero top margin because, well, I wanted it to have a non-zero top margin! I don’t blame the browser developers for complying to the standards; web designers demand and expect the browsers to be standards-compliant. Rather, I blame the standards developers for developing substandard standards. I can’t imagine what they were thinking. Anyway, the workaround for this bug, as I shall call it, is to give the parent block, in this case all_content, a non-zero border-top or padding-top. If the parent has a border or padding, then the top margin of the child does not adjoin the top margin of the parent, the margins do not collapse, and all is right with the world again.

Speaking of standards-compliance, I used to consider Mozilla’s Gecko, the rendering engine behind Camino and Firefox, the standards king. Perhaps it was, in the early days of Safari. I believe that Gecko has lagged behind while WebKit, the rendering engine underlying Safari and Vienna, among others, has caught up and surpassed it. While testing my web site in Camino, I ran into a couple of problems. First, Gecko doesn’t handle the inline-block display property. This bug has been open since 1999. I would advise web designers not to use inline-block if they want their pages to display properly in Gecko browsers.

Second, there is a bug, open since 2004, in how Gecko calculates percentage margins for a float with width: auto. You can see this by comparing how my résumé looks in Safari and Camino, under the “Degrees” heading, for example. (Is this a ploy to get you to read my résumé? No, just a happy coincidence.) Percentage margins are supposed to be calculated relative to the size of the containing block, but Gecko calculates them relative to the size of the float, so that the width of the margin is a percentage of the sum of the widths of the float and margin. This makes the margin far too small. My workaround, as you can see in the HTML source, was to increase the margin’s percentage size somewhat. It still looks too small in Camino, but I don’t want to make it too large in Safari. Although I could have used a table in this situation rather than floats, it made much more sense semantically to arrange the content by columns rather than by rows.

I hope that you enjoyed my rants, err, tips. I promise to talk about Cocoa programming in the next post. I also promise to lower taxes, raise spending, balance the budget, ask not what my country can do for me, fear nothing but fear itself (that is, the form of fear, not those shadowy particular fears), put a chicken in every pot, a car in every garage, and a kitten in every lap. Of course, this all depends on what the meaning of the word “I” is. I want a yacht. Thank you very much. Argh.

Stand and unfold yourself

Monday, October 9th, 2006

Hi, I’m Jeff Johnson. You may remember me from such projects as Vienna, an open source feed reader for Mac OS X. Software development will be the principal subject of this blog, so if you’re not a software developer, you’ll probably be bored by it. Even if you are a software developer, I can’t make any guarantees, but I’ll try to be as entertaining as possible. Bear in mind that I’m no ridiculous fish.

I started this blog for two reasons. First, and least important, I’ve wanted to share the coding tips and tricks I’ve learned through trial and error. By trial I mean a person, thing, or situation that tests a person’s endurance or forbearance. By error I mean a misplay by a fielder that allows a batter to reach base or a runner to advance. Although I love the powerful features and tools that the Cocoa development environment provides ‘for free’ (I also love the name—who wouldn’t want a warm, delicious cup of application frameworks?), the API documentation seems to be written according to the Strunk and White dictum, Omit needless words. In my opinion, Cocoa is to approached like a genie: it can do magic, but only if you can figure out what to wish for.

The other reason I started this blog is for blatant self-promotion. I recently switched fields from academic philosophy, so I need to do some networking. That’s what the net is for, right? (Uh, right?) As I said in my résumé, I’m looking for permanent or temporary work in computer programming or computer-related consulting, support, training, or writing. I would also accept a position in Quality Assurance, either computer-related or chocolate-related. Please contact me if you’re looking for someone in these areas, you know of someone who’s looking for someone in these areas, or you know of someone or are someone who could throw some money at someone in these areas or near my area. Thanks!

Disclaimer: No animals were harmed in the making of this blog. In fact, the maker of this blog was harmed (superficially) during the making of the blog by one particular animal with particularly long claws and a slight politeness deficit.