pbcopy and pbpaste

May 5, 2009

Here’s a quick tip about two handy command line utilities for Mac OS X: pbcopy and pbpaste.

pbcopy is used to capture output from any command line program and place it into the pasteboard. An example:

$ cat hello.txt 
hello world!
$ cat hello.txt | pbcopy 

We can now paste the output from cat in the regular cmd-v fashion mostly anywhere.

pbpaste, on the other hand, outputs the contents of the pasteboard. An example:

$ pbpaste 
hello world!

In this way, pbcopy and pbpaste can be used to move data between command line programs and GUI applications.

pbcopy and pbpaste have a few tricks up their proverbial sleeves. You can read all about them in their man page, which is available online, or simply by entering man pbcopy on the command line.

Update: Boy genius Mattias Arrelid pointed out that to get pbcopy and pbpaste to play nicely with UTF-8, you need to set __CF_USER_TEXT_ENCODING correctly. Read the full scoop over at Mac OS X Hints.

Cocoa sans Xcode and Interface Builder

March 3, 2009

Something that has always bugged me about Cocoa development is that it’s so tightly coupled with Xcode and Interface Builder. Virtually every single guide on the topic will use those two apps, and if you dare ask how one would go about without them, the answer will almost certainly be an exasperated “why would anyone want to do that?!”

And that’s something that bugs me even more. Good programmers love taking things apart to figure out what makes them tick, and I strive to be one. It’s not that I hate Xcode and Interface Builder, but rather that I like to understand what’s going on.

Turns out it’s not tricky at all.

Before we get started, let’s define what developing a Cocoa app without Xcode or Interface Builder actually means. No Xcode means we can use any editor and any build system we want. No Interface Builder means that we’ll be creating our views programmatically. Of course, these are three completely separate topics, and it’s quite possible to do just one or two of them. But let’s go the whole hog.

Objective-C, being a strict superset of C, has to obey every rule that C obeys. Hence, a truly minimal Objective-C program would be something along the lines of:

int main(int argc, char *argv[])
{
  return 0;
}

Of course, this doesn’t do anything interesting, and crucially, it’s not a Cocoa app.

Now, what makes a Cocoa app? Well, if you create an empty Cocoa app project in Xcode, main will contain a call to NSApplicationMain and nothing else. So, I suppose we could just stick that in our main, call it done and go out to lunch. But that would be cheating. Besides, what does NSApplicationMain do anyway?

It actually has an entry in the API reference, but that will not tell you much about what it does. That information is tucked away, for some reason, in the docs for the NSApplication class.

With this knowledge, and considering we’re not going to load any nibs, we can change the code for our minimal Cocoa app into something like this:

#import <Cocoa/Cocoa.h>

int main(int argc, char *argv[])
{
  [NSApplication sharedApplication];
  [NSApp run];
  return 0;
}

Save the above in a file called kakao.m and compile it with gcc like so:

$ gcc -framework Cocoa -o Kakao kakao.m

You can even run the app if you feel like it:

$ ./Kakao

Although, as you might have noticed, that won’t do much except hang until you kill it. So let’s add something more interesting, like a window.

After a quick look in the docs for the NSWindow class, we change the code for our app into this:

#import <Cocoa/Cocoa.h>

int main(int argc, char *argv[])
{
  [NSApplication sharedApplication];
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  NSUInteger style = NSTitledWindowMask
                   | NSClosableWindowMask
                   | NSMiniaturizableWindowMask
                   | NSResizableWindowMask;
  NSWindow *window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,400,400)
                                                 styleMask:style
                                                   backing:NSBackingStoreBuffered
                                                     defer:NO];
  [window makeKeyAndOrderFront:nil];
  [pool drain];
  [NSApp run];
  return 0;
}

Note that we create an NSAutoreleasePool before we create the window, and drain it afterwards. This is something Cocoa will usually take care of, but since we are not yet in an event loop, we have to do it manually.

Compile and run the program like before, and lo, a window appears!

However, this is clearly not a trüe Cocoa app yet. It doesn’t get its own icon in the dock or in the cmd-tab view, and if you try launching it from the Finder, things just get plain silly.

Of course, this is something we can fix. Applications, as well as many other kinds of bundles, are nothing but directories with special names in Mac OS X.

If you’ve ever peeked inside a .app bundle (right-click, Show Package Contents), you know it contains a directory called Contents, which contains among other things a directory called MacOS, which contains the actual executable for the app.

So, without further ado:

$ mkdir -p Kakao.app/Contents/MacOS
$ mv Kakao Kakao.app/Contents/MacOS/

And presto! You have a bonafide Cocoa app, complete with icon and menu bar (which is empty, but still) that can be launched from the Finder.

Now, if you have been digging around .app bundles before, you know that there are two more files that should go in there: Info.plist and PkgInfo. And yes, if you’re developing an actual app you plan on having actual users for, you should create those files as well. But for our purposes, we’ll do fine without them as long as the executable has the same name as the bundle, minus the “.app” suffix.

Oh, and in case you’re wondering, “kakao” is Swedish for “cocoa”.

Recommended reading

This is based on a presentation I gave at CocoaHeads Stockholm. If you’re into Cocoa, and live in or near Stockholm, you should drop by and say hi.