Drag If You Want To

June 7th, 2006

Handling drags to your Cocoa application is pretty simple: you just have to implement the informal NSDraggingDestination protocol in some view hierarchy object that has been registered for particular drag types.

Usually a drag is handled by a specific view that can make sense of the drag’s data type. For instance, an NSTextView will accept text from the dragging clipboard and plop it down into the edited documnt. Most of the time, drags should only be handled by these specific views, but sometimes it makes sense to intercept “unhandled drags” and make something useful happen for the user. For instance, when a user drags a URL to a web browser, you might as well assume that they want to open the URL, even if they carelessly let go somewhere in the browser window’s non-descript background texture.

Apple made it easy to handle such “drags of last resort” at the window level, by kindly passing along all dragging offers from NSWindow to the window’s delegate. If your delegate simply implements the required methods, you can snag and make useful any drag that would otherwise bounce back to the originator.

But handling such non-specific drags at any level lower than NSWindow becomes tricky. There is no corresponding “delegation” when it comes to NSView, so drags that hover over or release in an uncooperative view will not be accepted, even if you’ve asked the view to register for the desired types.

When you are faced with the desire to “stake out” part of a window’s real-estate as a drag destination, the simplest way to do so is to sneak a custom NSView into the hierarchy that does accept drags. But instead of writing a custom view every time you need to do this, why don’t we follow AppKit’s lead and write our own NSView subclass that makes use of the delegation strategy.

RSDragDelegationView (MIT License) is a very simple NSView subclass that does just this. To mark the background area of a part of your UI as dragging-receptive, just select items in Interface Builder and “make subviews of custom view.” Set the class of the custom NSView to RSDragDelegationView (drag the header file to your IB document to teach it about the class), and connect the “mDraggingDelegate” outlet to the delegate instance. From your delegate code, you can now ask the custom view to register for your desired drag types, and all dragging messages will be forwarded on to you as they’re received.

An example of where I use this in my own code is in the “product registration pane.” I want to accept drags generously, because I advise users to drag their product registration email into the window after they’ve paid. If they can’t figure it out, they might email me, and while I’m always up for a nice customer chat, I’d just as soon talk about other things. There’s no reason for me not to make this as error-proof as possible, so I stake out the entire space of the tab view item in which the pane is installed. By using a custom drag-enabled view I avoid inflicting drag receptivity on the rest of the window, and keep the dragging-related code right near the controller code for the UI that needs it. If another section of the window’s UI needs to accept drags liberally, the same trick can be applied without complicating drag-handling at the window level.

Livin’ in a WordPress Hacker’s Paradise

June 5th, 2006

I have been happily using WordPress as the infrastructure for this blog since its inception, almost one year ago. Since I’m perhaps slightly geekier than than the average WordPress customer, I have been wanting to get to know the sources a bit better and possibly make my own tweaks or write plugins to suit my particular needs. I also like to keep up to date with the latest versions of the software. The problem is that these activities are at odds with each other. See, if you don’t tweak anything, updating is a simple matter of “un-tarring” the package file over your existing installation and visiting the “update.php” URL. But if you’ve made any sneaky changes, you’re liable to overwrite them when you clobber a source file with the updated version.

This situation has led me to an unfortunate state of moaning about having to install WordPress updates. This is bad, because often the small updates contain security fixes, which are exactly the kind of thing I should want to install immediately. Furthermore, I’d like to stop editing WordPress with vi on the server, and searching the source base with grep. I’m proficient with these tools, but I have a Mac! It’s better at such things.

I need absolute WordPress control. Specifically, I need to be able to:

  1. Install WordPress updates with ease and confidence.
  2. Hack on WordPress and test results on my Mac before updating the live blog.
  3. Do so in a way that meshes with my regular work habits.

How do I address this? The problem screams for Subversion and Xcode, so that’s what I will throw at it. By integrating my WordPress hacking with Apple’s Xcode, I can treat the technical underpinnings of my blog just like I would any other code project. I spend so much of my day “building and running” that it’s distracting when any technical project does not fit in with that process.

Step 1: Get Things Under Control

Source control, that is. I decided that I needed a single repository where both my live web site and local Mac could access the same WordPress sources. That means I need an SVN server accessible from both locations, as well as Subversion client tools in each location. Luckily DreamHost comes standard with Subversion support (minor gripe: they’re stuck on version 1.1!). If your web host doesn’t offer Subversion, you might be out of luck for this particular round of magic.

Typically with Subversion repositories, the “mainline” of the project is identified as a subdirectory of the repository called “trunk.” In my case, I don’t control the mainline of WordPress, so I’m choosing more clear identifications. My repository is “all branches,” if you will, so I’m not including any folder called trunk, though “official” is the closest thing to being that:

% svn ls file:///home/jalkut/svn/opensource/wordpress/          
hacking/
official/
redsweater/
redsweater-assets/

What I’ve done here is take advantage of the “smart copying” in Subversion. I started the repository out with “official,” containing the latest 2.0.3 release of WordPress. I then copied that in the repository to “redsweater” and carefully copied all of custom bits and pieces in. If you do this right, only the customized parts take up repository disk space. Everything that’s the same is shared in the database. The custom bits include the database configuration, custom themes, installed plugins, images, etc.

Where possible, I took advantage of a feature in Subversion called “svn:externals.” This lets you specify points in the project hierarchy that, when encountered, will trigger a checkout from a different repository. It’s sort of like an NFS Mount-Point right in Subversion. In the mysterious “redsweater-assets” repository folder above, I’ve added folders for most of my custom elements. So when I checkout “redsweater” and Subversion gets down to the “themes” section, it notices that it needs to checkout my custom theme from the redswetaer-assets/themes repository folder. This technique works great in almost every area of WordPress, except for the plugins directory. Because svn:externals can only specify a directory, it breaks down when one would hope to use it to plop individual files down into a checked out directory. I imagine this limitation comes from the fact that every folder in a working directory has a single “.svn” folder for tracking the entries at that level. Therefore, a directory of assets from mixed repositories would be tricky.

Even with the svn:externals shortcomings, the setup works pretty well now. I have a “redsweater” branch that I can integrate changes into, and then update my web site directly from the command line. At any time, I can examine the differences between my customized branch of WordPress and the official release I last integrated with. Comfort!

Step 2: Integrate with Xcode

The Subversion infrastructure goes a long way toward calming my nerves about integration and updates. I can carefully stage any update by first updating and testing it on my local machine. That’s cool, but it’s not really good enough. I want to be able to hack the heck out of it on my local machine (Note: You need to install a PHP-compatible Apache server before you can really do this on your Mac). Furthermore, I want to possibly be able to maintain a separate, highly experimental copy of WordPress for days, weeks, or months while I continue to serve (and perhaps update) the more stable version of the blog from my site. It’s time to look at the “hacking” branch that I hinted at above.

The hacking branch started life as a copy of the redsweater branch. I want it to closely mimic my real blog, but I want to have freedom to mess around with it big time. So the first thing I altered after copying the branch over was the wp-config.php. Instead of pointing to my live database, I pointed to a local MySQL database on my Mac (yet another custom install, sorry!). This database contains a subset of my live blog’s content. The idea is it’s a totally safe sandbox for me to work in. I can add comments, posts, pages, etc. I can delete everything and start from scratch. I can even post drafts of my entries from MarsEdit to see how they’ll really look when they finally go live. The ultimate preview! One of the things I’ve noticed so far in hacking on WordPress is that I need to provoke different situations before I can play around with the behavior. For instance, if I want to tweak the spam-filtering behavior, I have to first cause a spammy comment to appear on the blog. I don’t like doing this on the live blog, but fake spam comments are fine in my sandbox.

What else does the hacking branch contain? This is where it gets fun. The branch contains an Xcode project file, and supporting shell scripts to facilitate a streamlined development process. First I added all the WordPress sources to the project, for easy global search & replace. It’s amazing how much faster you can get to know the project when you get a “birds-eye view” from Xcode:

I find that I understand a project much better even by doing simple tweaks like globally replacing something so that it behaves differently. When I can observe the changes, it connects my test changes to the project’s design as a whole.

Next up I attacked the problem of “fixing the workflow.” What does it mean to “build & run” a WordPress project in Xcode? I decided that building WordPress means “copying the files into my local web server directory,” and running it means “opening a suitable URL in my web browser.” To that end, I added a single target to the Xcode project, “Install Local,” which is a simple copy files build phase target. It takes all the specified files and plops them over to the “blog” subdirectory of my local test server:

Sweet! Now when I want to try out my changes, I can just press Cmd-B to build and then load up my localhost URL in Safari. But the scenario isn’t quite complete. When I build an application in Xcode, I don’t have to navigate to the Finder, find the resulting product, and double-click it. Why should I have to go manually reload this web page? With Xcode custom executables, I don’t. I added a couple shell scripts to my “hacking” tree that, when specified as custom executables, simply cause the local blog to open up in the default browser. This trick is accomplished with some simple AppleScript bridging:

#!/bin/sh
osascript -e "open location \"http://localhost/blog/\""

For every commonly debugged location in the blog, you can just pop another custom executable into the project with a slightly different blog URL. Then you select the desired executable from Xcode and “run” the project to see how your results are shaping up.

Now I can make changes, build, run, examine the results, and even use Xcode’s built-in Subversion features to review what I’ve changed!

If you want a head start at making your own WordPress hacker’s paradise, you can download and plop my WordPress Xcode Project files into your own local WordPress “hacking” directory. It should work just fine with a standard 2.0.3 copy of the sources. The archive includes the Xcode project itself as well as a couple example “executable” scripts.

Learn Python

June 2nd, 2006

I have never gotten very good at any of the popular shell scripting languages. Over the years, I’ve dabbled in Bourne sh scripts, Perl, awk, and sed. I was never one of those magical guys who could make anything happen in a few seconds. But I’ve always wanted that to change.

I’ve decided to learn Python. I want a fast-acting Swiss Army Knife at my disposal for splicing together the loose ends of my computer life.

Why Python? I don’t know it well enough to really sing its praises, but a number of influences caused me to veer towards this language (as opposed to say, improving my Perl or picking up Ruby):

  1. A Killer App. NodeBox was the catalyst for this whole pursuit, though it has nothing to do with productivity, per se. I downloaded NodeBox on the recommendation of a friend, and was instantly blown away that such a tool exists at all. NodeBox makes it easy to programatically produce graphics on the Mac, exploiting the Quartz graphics capabilities of the system. Python happens to be the language for driving these amazing dynamic documents.
  2. A Good Reputation. I started dropping Python references among groups of programmer nerds who I respect. Almost universally people either didn’t respond (people like me), or else raved about how great it was. About the only thing I ever hear people complain about with Python is its strict indentation rules. Hey. I’m a C programmer, but I have style. Indentation is OK by me.
  3. Support From “The Man”. I’ll admit it, I am more likely to embrace something if Apple does it first. It’s just easier to get involved and stay involved with a technology when you know that there will be value-added by the most influential company in your little neck of the tech woods. Apple has included Python with Mac OS X as a standard part of the system, and even gone so far as to provide special Python bindings in frameworks like Quartz to facilitate the above-mentioned scripting tricks. I can embrace this language without worrying that its functionality on the Mac will suddenly disappear.
  4. A Decent Tutorial. The biggest roadblock to learning for me is finding the start of a good path. If there is an incremental process I can follow to get better at something and eventually “know it,” then it’s much easier to tackle. The author of Python himself, Guido van Rossum, provides a short-and-sweet tutorial that made it easy for me to get to know Python.

I have a little trick with these “short chapters” tutorials. I keep a bookmark to the “next chapter” in my Safari bookmarks bar, and add reading it to my ToDo list for the following day. When I finish the chapter, I update the toolbar bookmark and wait until the next day. That way the learning is never overwhelming – just a few minutes aday, and it still only takes me a couple weeks to get through the whole tutorial.

This trick is OK, but while I was taking this tutorial, I got annoyed by having to constantly flash back and forth between the web page and my Terminal window. The Python tutorial introduces you to ideas that, if you’re anything like me, you immediately want to try out in the interactive shell. I decided to take a cue from Michael McCracken, who recently produced and distributed a dumbed down web browser just for reading Gmail.

Learn Python is a simple Mac OS X application (GNU License, source included) that puts a web browser and terminal window into one application. The web browser points at the aforementioned Python tutorial on the web, and it remembers the last URL you went to, so you can trust it to remember which chapter you were at when you last quit.

It’s a Python-Tutorial Browsing Machine!

By almost every possible measurement, this project was a “waste of time.” But sometimes you’ve got to make the software you wish existed, just so you know it does. I rationalize the time as well-spent since it sets me up to easily crank out one-offs of a similar vein as I find a use for them. If I was really bored I would probably have added “value added” buttons to the UI for specifically navigating the document structure (e.g. next chapter, etc). But I think I’m done for now. Hopefully most of the bugs are ironed out.

I hope some of you will get some use out of this extremely narrow piece of work. At least it might encourage you to learn Python!

PS: Unhappy with the default version of Python that gets launched? Or wish you could use the tool as a ruby or shell scripting or whatever tool? I haven’t put any preferences in this application, but it would be easy enough to hack the sources. If you aren’t feeling up to hacking the sources, or don’t have the tools handy, you can specifically override the path of the launched tool by editing the file “Localizable.strings” in “Learn Python.app/Contents/Resources/English.lproj/”. Inside this file, change the line:

"/usr/bin/python" = "/usr/bin/python";

That will tell the application to use zsh instead of python. Replace the “/bin/zsh” with whatever you want.

Update (June 3, 2006): The download has been updated to version 1.0.3, which now defaults to a left-right orientation for the web and python shell panes. The setting can be changed back to top-bottom through the preferences dialog.

Update (June 4, 2006): Rodney Ramdas posted a modified version of the application that is targeted at learning Ruby, instead. I’ll probably use it to tackle Ruby, next!

Andrew Stone Responds

May 31st, 2006

I had an off-line chat with Andrew Stone, to see what his reaction was to my recent entry about the design of Videator. He agreed to let me publish his response here as a counterpoint to my pretty strong criticism. He makes some good points and at the end of the day, he’s right: it’s best to download and try it out for yourself.

Thanks, Andrew!


Thank you for all the attention you have lavished on Videator.

I would ask you to consider people’s motivations in dissing both the application and me personally so vehemently. Why was such an emotional response generated by this new application? Should I be flattered that my work is not being ignored? Do I win points for touching raw nerves? ;-)

Working with the metaphor, batshit is an extremely rich source of nitrogen prized by gardeners. My software and the ideas contained therein is organic fertilizer for the software world. And in Jazz lingo, no higher complement than ‘crazy’.

I’m one of the last truly independent developers who has scratched out a living for 18 years innovating ideas which quickly get re-used and popularized by larger, better-funded software houses. I rely on good word-of-mouth to continue to get sales, so of course, getting such negative publicity is painful for more than just the ego.

When a new application comes along that does things that no other application has done before, of course there are going to be complaints about the way we decided to implement it! You have some valid design points of course, I am not attempting to deny that. However the emphasis on the exterior drowns out all the core brilliance of what the application can actually do.

It’s as though no one actually used the application but simply decided to trash it from the screenshots or their personal distaste for my independent status. The power of Videator is that it’s not a “limited choices – canned settings – just click here” kind of app Mac users have become so comfortable with. Those types of applications are easy to apply the design guidelines you mention.

Alas, Videator is breaking new ground and is perhaps outside the comfort zone of the armchair critic. Providing a set of tools to do almost unlimited manipulation of video, Videator takes on a very complex domain. Could the UI be tweaked to better? Certainly.

BTW – for people who don’t like polished metal, there is a switch in Preferences to get Aqua windows…

Why not focus on what’s cool and innovative about the application? I encourage people to download and try it for themselves – it’s free for 2 weeks and then just $49 and free upgrades for life – where new and better UI’s will no doubt emerge, it’s still a deal.

Download it now – or learn more at:http://videator.com