Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing a Snow Leopard Service for Finder.app

I am currently looking into solving the problem with the inability to quickly create new files in the Finder. I will open source what I write because I think the Mac community needs this solved.

On Windows, you can right-click, create new text file. OS X, you should be able to do this with a service which would work like this:

  • Right-Click > Services > Create New Text File

Writing a Finder Service in Snow Leopard is theoretically the way to accomplish this, although I haven't been able to find any sample code. (I'll admit I've only looked at the documentation very briefly).

I'm not sure how to get started, whether Apple provide a Services template in Xcode. Basically I'm looking for help with getting a working services project running. The implementation code should then be rather trivial for me to write in Obj-C. So what can I do to create a new working Services project? If i'm wrong about this then tell me the right way to do this and please provide sample code or some steps to get me started.

Edit: Trust me guys, I'm not an OS X noob. Have tried many apps to achieve work arounds: PathFinder, Automator, Terminal,etc and I'm happy with none of them.

I want to create a right-clickable menu item for creating New files, the same as Windows has. If this API doesn't let me do this, then I will modify system files if necessary. But I would rather do it in such a way that doesn't require me hack OS X.

The sad fact is that Apple disabled 3rd party contextual menu items when Snow Leopard was released and devs weren't happy. You could create services under the contextual menu with Automator, but it was very limited.

Yes, Quicksilver is the way I create files at the moment, unless I'm in the terminal when I touch ~/Desktop/file.txt or wherever.

If you cannot answer my question by providing source code for an Xcode project for writing a Service, please keep your opinions on how I should be using my computer to yourself. At any rate, I think I will probably be answering my own question after I go and implement this myself.

like image 688
Brock Woolf Avatar asked Sep 17 '10 01:09

Brock Woolf


1 Answers

Read Services Implementation Guide. If you want a working sample code, see this project I cooked up. As explained in the guide, what you need to do is to install the service handler:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    [NSApp setServicesProvider:self];
    NSUpdateDynamicServices();
}

- (void)handleServices:(NSPasteboard *)pboard
          userData:(NSString *)userData 
         error:(NSString **)error {
    if([[pboard types] containsObject:NSFilenamesPboardType]){
        NSArray* fileArray=[pboard propertyListForType:NSFilenamesPboardType];
            // do something...
    }
}

and advertise it in your Info.plist:

<key>NSServices</key>
<array>
    <dict>
        <key>NSMenuItem</key>
        <dict>
            <key>default</key>
            <string>Service Handling Demo</string>
        </dict>
        <key>NSMessage</key>
        <string>handleServices</string> <!-- This specifies the selector -->
        <key>NSPortName</key>
        <string>services</string>       <!-- This is the name of the app -->
        <key>NSSendTypes</key>
        <array>
            <string>NSFilenamesPboardType</string>
        </array>
    </dict>
</array>

It's as easy as this! You might need to manually turn on the service entry in the Keyboard Shortcut section of the System Preferences.app. If you want to turn it on automatically, you can write into pbs.plist inside Library/Preferences/, but that's not a documented way of doing things.

The problem is that Finder doesn't show this service item when you right-click an empty region in the Finder window. You can't do anything with it, other than injecting the code. This is inherent in the Finder's support of the service system. If you want to change that behavior, you need to inject code inside Finder.app. That's not that hard. On Snow Leopard, it's standard to use the OSAX loading trick, described at e.g. in this blog post. Then you can use Objective-C runtime functions to patch the behavior of the right-clicking of the Finder, by changing the methods described in this Apple document. (I don't know which of the method Finder uses to respond to the right-click event, though.)

Instead, if you're OK with clicking a button on the toolbar of the Finder window instead of right-clicking, you can add a button, as in this utility cd-to. This uses the ability to put an icon of the app to the Finder toolbar. The app itself just reads the path of the frontmost Finder window via Apple events, and opens a Terminal window for that. I think you can tweak the code of this app to do what you want.

Here follow subjective stuffs:

Honestly, you don't have to use Objective-C to write a Finder service if you just want to make a new file. Automator can do the same thing with a shell script and/or Applescript.

If you want to manage files efficiently on Mac, there are already great utilities around: try Butler or launchbar or Quicksilver, for example.

like image 116
Yuji Avatar answered Nov 02 '22 13:11

Yuji