Matt Rajca

Sep 05 2011

Auto-Ejecting Disc Image Files Dragged to the Trash

Even with the growth of the Mac App Store, I still find myself constantly downloading, mounting, and eventually trashing DMGs. Almost just as frequently, I am greeted with the following dialog whenever I try to empty the Trash with mounted disc image files inside it:

Disc Image in Trash

Fortunately for us, we can overcome this annoyance by creating a Folder Action in Automator. Folder Actions run whenever the contents of a specified directory change – in this case, the current user’s Trash. Any mounted disc image files found inside the Trash will get ejected automatically by our Folder Action.

  1. Open Automator, which can be found inside the Applications directory.
  2. Create a new document and select ‘Folder Action’ from the template chooser.
  3. Click on the ‘Choose folder’ pop-up button and select ‘Other…” from the menu that appears.
  4. When the ‘open’ panel comes up, hit Shift+⌘+G and enter ~/.Trash in the location field; click ‘Go’, followed by ‘Choose’.
  5. Drag a new instance of the ‘Run Shell Script’ action (listed under the Utilities group) from the Library into your workflow.
  6. Set the action’s shell to /usr/bin/python and its input type to ‘as arguments’.
  7. Finally, replace the contents of the placeholder script with the one listed below.

import string, os, sys

lines = os.popen("hdiutil info").readlines()
should_eject = False

for line in lines:
    if line.startswith("image-alias"):
        path = line.split(":")[1]
        image_path = path.lstrip().rstrip()

        if image_path in sys.argv:
            should_eject = True

    elif line.startswith("/dev/") and should_eject is True:
        os.popen("hdiutil eject %s" % line.split()[0])
        should_eject = False

    elif line.startswith("###"):
        should_eject = False


After your new Folder Action is saved, any mounted disc image files dragged to the Trash will get ejected automatically.

12 notes

Sep 01 2011

Kinect Support for Extreme Tux Racer

Recently, I took a short break from my long-term projects to play around with the official Kinect for Windows SDK. As a mini side-project, I added Kinect support to a classic open source game, Extreme Tux Racer. As Tux accelerates down the racetrack, the user can tilt his or her head left or right to steer the penguin, lean forward to paddle, and lean backward to brake. Tux Racer’s lenient collision detection logic also tends to work in the user’s favor during gameplay. If you’re interested in the project, take a look at the source on github, or check out this quick and rough video of it in action! Kinect support is only available on Windows at the moment.

5 notes

Aug 14 2011

LLVM, Code Coverage, and Xcode 4

The ability to generate code coverage reports has been one of the notable features missing from the LLVM/Clang compiler. As of June 8, 2011, the Clang frontend can finally generate code coverage reports using the same flags that were supported by GCC. At the time of this writing, these flags haven’t made their way into Xcode’s build settings UI. I have no doubt they will be integrated into a future release of Xcode, but until that happens, we can always compile our own build of Clang and manually pass in the compiler flags necessary to generate code coverage reports.

Below are the steps required to check out, compile, and install the tip-of-tree build of LLVM/Clang.

# check out the source to LLVM
svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm

# check out the source to Clang
cd llvm/tools
svn co http://llvm.org/svn/llvm-project/cfe/trunk clang

# configure the project for compilation
cd..
./configure --prefix=/opt --enable-optimized
make -j8           # build with 8 threads
sudo make install  # install to /opt

If all goes well, a new binary of the Clang compiler should now reside in /opt/bin/. Next, we need to tell Xcode to use our newly-built compiler instead of the build it ships with. This should be done for each target you want to generate code coverage reports, or at the project level. In Xcode, open the Build Settings pane of the desired target and choose ‘Add Build Setting’ from the bottom toolbar; select ‘Add User-Defined Setting’ from the pop-up menu that appears. Enter CC for the setting name and /opt/bin/clang as its value. Xcode will now build the target using our custom-built compiler.

Xcode 4 CC Setting

While we’re in the Build Settings pane, find the Other C Flags setting and add -fprofile-arcs and -ftest-coverage on to the list. These flags will tell Clang to generate gcov files for each class in our target.

Lastly, we have to link against libprofile_rt.a (instead of libgcov.a, which was required by GCC). In Xcode 4, switch to your target’s Build Phases pane and expand the ‘Link Binary With Libraries’ section. Click on the ‘Plus’ button, choose ‘Add Other’, and navigate to /opt/lib. Select libprofile_rt.dylib from the list of files.

And that’s it! If you build and run your target, Xcode will now output gcda and gcov files to a well-hidden path inside the DerivedData directory. To find it, right click on your target in Xcode’s Products group, and select ‘Show in Finder’. Navigate up the path hierarchy to the Build folder, as shown below.

Target Build Folder

Finally, open up the Intermediates/$TARGET.build/$CONFIG/$TARGET.build/Objects-normal/$ARCH subfolder. Inside, you’ll find the aforementioned gcda and gcov files. Since Clang outputs these files in the same format as GCC, they are compatible with tools such as CoverStory.

32 notes

Jul 09 2011

Adding Code Completion Support to TextMate Bundles

Code completion isn’t a prominent feature in TextMate, but it exists. If you enter some text and hit ‘Escape’ repeatedly, TextMate will cycle through any available code completions. Unfortunately, this only works with the Objective-C and PHP bundles, and all functions and methods suggested exclude parameter lists. Compared to the code completion system in Xcode 4, this isn’t very impressive.

After searching around, I discovered that the PHP bundle does something clever: if you hit ‘Option+Escape’ or select the ‘Completions for Word…’ menu item from the bundle’s action pop-up, TextMate will present a menu of available code completions.

TextMate code completion

What’s more is, once a completion is accepted, the name of the function along with any parameters will be inserted. You can even tab through each parameter, just like in Xcode! After digging around in TextMate’s Bundle Editor, I was surprised to find that the code to make all of this happen is only 5 lines long:

#!/usr/bin/env ruby -wKU
require ENV['TM_SUPPORT_PATH'] + '/lib/osx/plist'
require ENV['TM_SUPPORT_PATH'] + '/lib/ui'

choices = OSX::PropertyList.load(File.read(ENV['TM_BUNDLE_SUPPORT'] + '/functions.plist'))
TextMate::UI.complete(choices, :initial_filter => ENV['TM_CURRENT_WORD'], :extra_chars => '_')

It turns out TextMate has built-in support for this menu-based code completion UI in its ui.rb support file — and it works pretty darn well. The completions are stored in the referenced plist file, whose structure is pretty self-explanatory:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
    <dict>
        <key>display</key>
        <string>ArrayMin</string>
        <key>insert</key>
        <string>(${1:const variant &amp; src[]}, ${2:unsigned int idx}, ${3:unsigned int len})</string>
    </dict>
</array>
</plist>

The value of the display key contains the name of the code completion item as it will appear in the list. Additionally, the value of the insert key contains an ordered list of parameters, which will be inserted whenever a code completion is accepted.

By leveraging this, I managed to add menu-based code completion support to a NXC bundle I’m working on, all in a matter of minutes. It’s a shame that so few TextMate bundles utilize this hidden gem.

18 notes

+

AppKit Quick Tip: Populating the ‘Open Recent’ Menu in Non-Document-based Applications

While writing Nibble, my native Apple I emulator for Mac OS X and iOS, I realized an Open Recent menu would be beneficial to users who want to quickly open recently-loaded memory dumps. In standard Document-based applications, AppKit automatically registers newly-opened files as recents. Unfortunately, it doesn’t make much sense to make an emulator a Document-based application.

Luckily, even Non-Document-based applications contain an Open Recent menu, ready to be populated. Moreover, NSDocumentController makes it extremely easy to register recently-accessed files through its noteNewRecentDocumentURL: method. AppKit will magically append the file at the passed URL to the Open Recent menu; it will even enable the Clear Menu item when necessary! When the user selects a recent file, AppKit will invoke the application:openFile: method on NSApplication’s delegate object.

The complete code listing can be found below:

NSDocumentController *dc = [NSDocumentController sharedDocumentController];
[dc noteNewRecentDocumentURL:[NSURL fileURLWithPath:somePath]];


- (BOOL)application:(NSApplication *)sender
           openFile:(NSString *)filename {

    // load the file

    return YES;
}

3 notes

+

Enabling VNC on a Mac with a Broken Display

Around two weeks ago, my iMac’s display started turning itself off at random times. I thought this was a software bug as I was running the latest beta of Mac OS X, so I ignored the issue. Doing a quick restart always restored everything to normal. A few days later, the display wouldn’t turn on at all. The Mac would still run and I could hear Alex speak the time every half hour. I ended up ordering one of the latest quad-core, 27” iMacs, but I still wanted to get some work done before it arrived.

If I could enable screen sharing, I would be able to work from my Ubuntu box via VNC. So I hit ⌘-Space bar to bring up the Spotlight search box on the iMac. I typed Terminal and hit ‘Return’, all while staring at a pitch-black screen. To check on the state of things, I would periodically pipe the output of commands to the say command, which would in turn speak the input. For example,

pwd | say

would speak the path of the current working directory. Next, I enabled ARDAgent to start the screen sharing agent (normally enabled in System Preferences):

cd /System/Library/CoreServices/RemoteManagement
sudo ./ARDAgent.app/Contents/Resources/kickstart \
-activate -configure -access -on -clientopts -setvnclegacy -vnclegacy yes \
-clientopts -setvncpw -vncpw PASSWORD -restart -agent -privs -all

After a quick reboot, I was able to start a VNC connection from Ubuntu 10.10 to Snow Leopard. Of course, if you have another Intel Mac and a spare FireWire cable in the house, you can always boot up the defective Mac using Target Disk Mode.

All in all, I still managed to crank out a few more Xcode builds of some of the projects I’m working on, until my new iMac arrived.

8 notes

Jul 01 2011

AppKit Quick Tip: Highlighting an Entire NSTableView When Dragged Over

When a user drags any form of data onto a NSTableView configured as a drop destination, the data can be dropped above or on top of any row. Sometimes, it may be preferable to highlight the entire table when a drag enters its bounds, as shown below.

NSTableView Drag and Drop

To accomplish this, set your drop row to -1 in the tableView:validateDrop:proposedRow:proposedDropOperation: method, which is a part of the NSTableViewDataSource protocol.

- (NSDragOperation)tableView:(NSTableView *)tableView
                validateDrop:(id < NSDraggingInfo >)info
                 proposedRow:(NSInteger)row
       proposedDropOperation:(NSTableViewDropOperation)dropOperation {

    [tableView setDropRow:-1 dropOperation:NSTableViewDropOn];

    return NSDragOperationEvery;
}

6 notes

+

App Engine Notes

Earlier today, I released fb2cal, a web app that lets users view their Facebook friends’ birthdays right from a native calendaring client. Coming from a desktop development background, writing a web app on top of App Engine was a new experience for me. Some points to take away:

  • Extend templates to reuse large parts of common HTML code; think inheritance
  • Leverage the memcache when making large data store queries or performing network requests
  • To serve parts of a web app using HTTPS, add secure: always to the script handler in app.yaml

And lastly, to handle basic authentication in a subclass of RequestHandler:

auth = self.request.headers.get('Authorization')

if not auth:
    self.response.set_status(401, message="Authorization Required")
    self.response.headers['WWW-Authenticate'] = 'Basic realm="Secure Area"'
    return None

parts = auth.split(' ')
username_pass = base64.b64decode(parts[1]).split(':')

username = username_pass[0]
password = username_pass[1]

# validate username and password...

Overall, I was extremely pleased with how fast, easy, and inexpensive it is to host a fully-functional web app on App Engine.

3 notes

+

Quick and Dirty Profiling with Blocks

Instruments is an amazing tool for finding all sorts of performance issues in your applications, but sometimes, all you want to do is log a quick and dirty timing of a snippet of code.

Mark Darlymple once posted a quickie that does just this. Unfortunately, the code isn’t very reusable. Each time you want to profile a chunk of code, you need to wrap it in nearly 8 lines of boilerplate code.

By writing a profile function that takes a block of work as an argument, this problem becomes trivial.

void profile (const char *name, void (^work) (void)) {
    struct timeval start, end;
    gettimeofday (&start, NULL);

    work();

    gettimeofday (&end, NULL);

    double fstart = (start.tv_sec * 1000000.0 + start.tv_usec) / 1000000.0;
    double fend = (end.tv_sec * 1000000.0 + end.tv_usec) / 1000000.0;

    printf("%s took %f seconds", name, fend - fstart);
}

To profile some code, all we now have to do is call profile and pass our worker block; the timing will get logged to standard out.

profile("Long Task", ^{ performLongTask() } );

20 notes

+
Page 1 of 2