Launch Finder window with specific files selected - objective-c

I'm trying to programmatically launch an OS X Finder window from an Xcode project. I need the window to open to a specific folder and have specific files within that folder automatically selected.
This is similar to the "Show in Finder" functionality used in Xcode and related apps.
Does anyone know how to do this in either Objective-C, Swift, AppleScript, or Finder command-line parameters?

Objective-C version:
NSArray *fileURLs = [NSArray arrayWithObjects:fileURL1, /* ... */ nil];
[[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:fileURLs];

$ open -R <path-to-reveal>

Another AppleScript flavor - the Finder's reveal command will both open a window to the containing folder and select the item(s). If there are multiple containing folders, multiple Finder windows will be opened.
tell application "Finder"
to reveal {someAlias, "path/to/POSIXfile" as POSIX file, etc}

Swift version:
let paths = ["/Users/peter/foo/bar.json"]
let fileURLs = paths.map{ NSURL(fileURLWithPath: $0)}
NSWorkspace.sharedWorkspace().activateFileViewerSelectingURLs(fileURLs)

I'm finding that activateFileViewerSelectingURLs is not working on Yosemite (at least when in separate space from Finder). It will cause a switch to the Finder's space but won't seem to select the URL. Using:
- (BOOL)selectFile:(NSString *)fullPath inFileViewerRootedAtPath:(NSString *)rootFullPath
will switch spaces from full screen app and select path.

When opening a file at path:
NSString* path = #"/Users/user/Downloads/my file"
NSArray *fileURLs = [NSArray arrayWithObjects:[NSURL fileURLWithPath:path], nil];
[[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:fileURLs];

Swift 3.2/4.0 Version:
NSWorkspace.shared.activateFileViewerSelecting([outputFileURL])

Reveal multiple files in Finder
As open -R <path-to-reveal> only works for single file.
We can use Apple Script instead.
From user866649's answer, we can port it to a shell script as the following:
osascript -e 'tell application "Finder" to reveal {"path/to/file1" as POSIX file, "path/to/file2" as POSIX file} activate'
Just created a utility script:
finder.sh
#!/usr/bin/env bash
join() {
local d=$1 s=$2
shift 2 && printf %s "$s${#/#/$d}"
}
lst=()
for f in "$#"; do
lst+=("\"$f\" as POSIX file")
done
files=$(join , "${lst[#]}")
osascript -e "tell application \"Finder\" to reveal {$files} activate"
Then try it:
chmod +x finder.sh
./finder.sh ~/Downloads ~/Desktop
It should open Finder and selects both Downloads and Desktop folder.

Related

How to enable FinderSync Extension in macOS System Preferences

I am integrating FinderSync Extension in my Cocoa Application to show badges in files and folders. Look at the below two scenario:
When i run application using FinderSync Extension (like DemoFinderSync) look at the blue popup in the below image, in that case Extension is added in the System Preference with Check mark and called that principal class "FinderSync.m" as well.
When i run application using my Application Scheme (like DemoApp) look at the blue popup in the below image, in that case Extension is added in the System Preference but without check mark and that principal class "FinderSync.m" do not call and FinderSync Extension does not work in this case.
Does anybody have an idea how to enable Finder Extension in the System Preference using second scenario?
Non-debug scheme (#if !DEBUG):
system("pluginkit -e use -i com.domain.my-finder-extension");
When running under debugger give path to your extension directly:
NSString *pluginPath = [[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:#"My Finder Extension.appex"];
NSString *pluginkitString = [NSString stringWithFormat:#"pluginkit -e use -a \"%#\"", pluginPath];
system([pluginkitString cStringUsingEncoding:NSUTF8StringEncoding]);
Specify this in your applicationDidFinishLaunching method. You should also manually turn this on only once so that if user turned your extension off in the System Preferences you don't turn it on every time your application starts. I set an NSUserDefaults key the first time user launches my app that has the finder sync extension support.
I got the solution:
Code to Enable Extension (bundle ID)
system("pluginkit -e use -i YourAppBundleID")
Code to Disable Extension (bundle ID)
system("pluginkit -e ignore -i YourAppBundleID")
Before i used:
system("pluginkit -e use -i AppBundleID.FinderSync")
so just remove ".FinderSync" its working.
Linking an answer I found on the Apple developer forum:
https://forums.developer.apple.com/thread/77682
When your App is outside the Sandbox, you can use:
Objective-C:
system("pluginkit -e use -i <yourFinderExtensionBundleID>");
Swift:
let pipe = Pipe()
let task = Process()
task.launchPath = "/usr/bin/pluginkit"
task.arguments = ["-e", "use", "-i", "<yourFinderExtensionBundleID>"]
task.standardOutput = pipe
let file = pipe.fileHandleForReading
task.launch()
let result = NSString(data: file.readDataToEndOfFile(), encoding:

Finder Sync Badge Extension Handling

I am trying to create a Finder Sync Extension,in yosemite to show badge in files and folder.
I am on the move, but i have no idea how to turn off extension(remove from extensions list in preferences) when my containing application terminate. Any help is appreciated.
Try it..
Reload Directory in Finder
// Reload Finder (change the word directory to file if updating file)
NSAppleScript * update = [[NSAppleScript alloc] initWithSource:[NSString stringWithFormat:#"tell application \"Finder\" to update POSIX directory \"%#\"",path]];
[update executeAndReturnError:nil];
Code to Enable Extension (bundle ID)
system("pluginkit -e use -i com.xyz.finderExt")
Code to Disable Extension (bundle ID)
system("pluginkit -e ignore -i com.xyz.finderExt")
code to remove from extensions list in preferences
pluginkit -r "/Applications/App-name/Contents/Plugins/extension-name.appex"

Unable to find running application in Cocoa

I am getting the list of running applications in Cocoa with the following code:
for (NSRunningApplication *app in [[NSWorkspace sharedWorkspace] runningApplications]) {
MNSLog(#"%#",[app localizedName]);
}
However an application I started from a terminal session is not appearing in the list ('Terminal' is well appearing). The application was started from the same user which is executing the cocoa code.Is my launched application under Terminal ? And in such a case how can I find its name and arguments ?Running ps in another terminal session show my process properly.
Use an NSTask to execute the ps Shell command. You can check the ps man page to determine which arguments you want to pass it based on the information you want to get back. Use NSPipe and NSFileHandle to get the results from the task.
If you want to do some filtering you can pipe the ps output through grep before your app picks up the result.
For your first question, I think NSWorkspace can only see apps that use the window server so you will only see Terminal, not the executables that it is running internally.
You can use sysctl or ps command to get a list of all BSD processes. Have look at unable to detect application running with another user

Use dolphin (or other browser) like yakuake

I often want to open a file browser to open a file and then close the browser.
Is there a way (a plasmoid, a dolphin plugin, another browser...) which could allow me to have a file browser "in the style of" yakuake? (i.e. unfolding with a shortcut, and re-folding when I chose the file I want)
Took me some time, but finally managed to get what you want (and eventually, what I also want :) with xdotool (on Ubuntu sudo apt-get install xdotool).
With this script, you can have any application behave like you asked:
#!/bin/bash
SEARCHED_WINDOW=$1
COMMAND=${2:-$SEARCHED_WINDOW}
SEARCHED_WINDOW_CLASSNAME=toggleApp$SEARCHED_WINDOW
WINDOW_ID=$(xdotool search --classname $SEARCHED_WINDOW_CLASSNAME)
VISIBLE_WINDOW_ID=$(xdotool search --onlyvisible --classname $SEARCHED_WINDOW_CLASSNAME 2>/dev/null)
if [ -z "$WINDOW_ID" ]; then
$COMMAND 2>/dev/null &
pid=$!
NEW_WINDOW_ID=$(xdotool search --onlyvisible --sync --pid $pid 2>/dev/null)
xdotool set_window --classname $SEARCHED_WINDOW_CLASSNAME $NEW_WINDOW_ID
xdotool windowfocus $NEW_WINDOW_ID
elif [ -z "$VISIBLE_WINDOW_ID" ]; then
xdotool windowmap $WINDOW_ID
xdotool windowfocus $WINDOW_ID
else
xdotool windowunmap $VISIBLE_WINDOW_ID
fi
(Inspired from here)
You call it like this:
./toggle.sh dolphin
If the command to launch the program is different, you can add a second parameter:
./toggle.sh appName commandToLaunchApp
What this script does is the following:
If the app is not running: launch it, give window a specific class, and give window focus
If the app is running but with no visible window: make window visible and give it focus
Else, i.e. app is running and visible: hide it.
All you have left to do is map a shortcut to the above-mentionned command to launch the script. In KDE : System settings > Shortcuts and gestures > Custom shortcuts. Then Edit > New > Global shortcut > Command.
Plus, this script works with any app, should work with any EWMH compliant window manager, and allows you to have other instances of the same app (this is why I added the class trick).
The closest solution to what you want is the Widget Layer Compiz plugin.
This plugin enables you to make appear a layer on top of your workspace. You can configure this layer to hold windows of your choice, in your case that would be the file manager. It has a hide/show feature which you can bind to a hotkey.
It uses Window Matching rules to define the windows to hold.
More information on http://wiki.compiz.org/Plugins/Widget
However, this would imply that you use the Compiz compositing manager.

How to set default application for specific file types in Mac OS X?

In Mac OSX lion, I'm trying to set default application for specific file types.
Using the below apple script, we can set the default application for the specific "file.abc".
tell application "System Events"
set default application of file "/Users/test/Desktop/file.abc" to "/Applications/TextEdit.app"
end tell
But I want to set the same application as default for all the files having the filetype or extension as "abc".
I have tried the following to get it done. It added an entry in <HOME>/Library/Preferences/com.apple.LaunchServices.plist. But the files are not opened with the specified application.
defaults write com.apple.LaunchServices LSHandlers -array-add "<dict><key>LSHandlerContentTag</key><string>abc</string><key>LSHandlerContentTagClass</key><string>public.abc</string><key>LSHandlerRoleAll</key><string>com.apple.textedit</string></dict>"
Hope somebody knows what i m missing to achieve it.
Answer Found :
defaults write com.apple.LaunchServices LSHandlers -array-add "<dict><key>LSHandlerContentTag</key><string>ugurugu</string><key>LSHandlerContentTagClass</key><string>public.filename-extension</string><key>LSHandlerRoleAll</key<string>org.videolan.vlc</string></dict>"
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain local -domain system -domain user
Maybe you're doing nothing wrong but that the com.apple.launchservices file just needs to be reloaded. You can logout, wait a few minutes or force launchservices to restart. In the following example I say that public.comma-separated-values-text files (note:This doesn't mean that every CSV file is this content-type) must be opened with TextEdit instead of Excel.
do shell script "defaults write com.apple.LaunchServices LSHandlers -array-add '{ LSHandlerContentType = \"public.comma-separated-values-text\"; LSHandlerRoleAll = \"com.apple.TextEdit\"; }'"
do shell script "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -kill -r -domain local -domain system -domain user"
I'm not sure if you're only trying to do this programmatically. Are you?
Otherwise:
On the file, choose "get info", and under "open with" select the name of the application.
Click on the button "Change All"
You might want to take a look at RCDefaultApp and its source code. It's a program that lets you set which file types are opened by which apps in Launch Services.