Is it possible to embed Finder functionality in a cocoa app, now that Finder is itself cocoa (assuming the app were to function only in snow leopard)?
What I mean is to have a file browser pane as part of the app, actually browsing the file system itself (to edit in another pane), but without writing all the functionality of the Finder. Thanks!
The Finder itself is just an application. It is not a components library nor a framework. While you cannot "embed" Finder functionality in your application, you can influence Finder functionality and invoke Finder functionality.
First off, you can attach Folder Actions to folders. These will trigger when a user does something to the contents of a folder - for instance, they drop a file into it. You set this up in the Finder. You should to learn a little AppleScript, if interacting with the Finder is something you want to do.
Second, since the Finder supports AppleEvents, you can affect the Finder using AppleScript. Take a look at My First AppleScript and My First AppleScript Part II to see how to do this. Here is much more in-depth information, in AppleScript Overview: Scripting with AppleScript. Here is some More Finder Scripting.
Third, there is also support for developing ways for the Finder to do complex things for the user at the click of a button, using Automator (Mac OS X 10.5). You can also create a Service in Automator, beginning in Mac OS X 10.6 ("Snow Leopard"). Take a look at Automator and Finder Actions in Mac OS X 10.6 for an introduction to this latter technique.
Even though Finder windows themselves are not an embeddable component, if you really want to provide the ability to pen, Print, Delete, Duplicate, etc. Files/Folders, and navigate from Folder to Folder, you can develop a simple Folder browser in your application.
It should not be a huge amount of work to do this so long as you do not set your sites on mimicking the finder or duplicating all of its functionality, just the essential basics I have mentioned.
You would need to know how to program the Macintosh, however - not just use AppleScript. The normal way to do this would be to learn the Objective-C programming language and the Cocoa framework. You would need to get familiar with writing applications using a Model-View-Controller architecture.
You would create a subclass of NSObject named something like MyFile, and a subclass of a collection class named something like MyFolder. When the application creates the browsing Windows, and each time the application activates (becomes the frontmost application), you8 would refresh the contents of the browsing menu.
You could put a menu in your menu bar with commands in it: Open, Print, Delete, Duplicate. When the user does one of those commands, your application performs the appropriate actions itself or sends the request to the Finder. After the action has been completely carried out, then you refresh the browsing window for currently displayed Folder, or newly displayed Folder if the user navigated to a different Folder.
If you are familiar with design patterns, object-oriented programming, and frameworks in general - reading up on Cocoa Design Patterns will speed your learning curve immensely.
These are various techniques you can use to harness some of the power of the Finder. As you look these over, I suggest getting very clear in your mind just what benefit this brings to the user of your application. Writing down what the overall objective of this feature is, and what commands you wish to support, will make it easier to choose the path you take in developing it.
The user can always click on a Finder folder window at the click of a button, since Finder is always running. So avoid simply duplicating that functionality for its own sake. Focus on the benefit you are providing the user. Make sure that you do handle the situations where the user updates the Folder you are showing the contents of from another application and then switches back to your application.
No, they have not made Finder simply a host for a framework, like Preview. You still have to write this yourself.
Related
On Mac it is usual that there is a "hidden" main window.
The usual example is "Text Edit". When you open a file you with you don't see a "main frame". Instead every single file will be opened in its own "Text Edit" instance. This is OSX way of emulating the so-called MDI interface.
However, there is an exception. If you open Xcode and open the project there, you can click on the file and it will be open inside the main Xcode window. And if you double click the file it will be opened in its own independent editor window, keeping the main Xcode window visible.
My question would be: do I need to do anything special in order to make my program behave like an Xcode? Should I use different class for the main frame or maybe react differently on the opening document event?
Any hints/pointers where to look or even to the official Apple documentation would be helpful.
The TextEdit behavior you're describing is much more like “SDI” than “MDI”, and the terms “SDI” and “MDI” weren't even needed until Microsoft invented MDI long after Xerox invented the SDI-type interface of which macOS is a derivative.
Anyway, I think you are misunderstanding Xcode's behavior. You seem to think “its own independent editor window” is a different kind of window than “the main Xcode window”. But in fact the new window is of the same kind as the old window, with some optional parts hidden. You can show those hidden parts and make the new window look exactly like the old window. Demo:
The ability to open multiple windows showing the same document (or, in Xcode's case, project) is a matter of software architecture. If you carefully design your app so that multiple windows can share a single model object graph, and can be notified and redraw themselves when the object graph changes, then you have an app that supports multiple windows showing the same document. If you want multiple kinds of windows showing the same document, nothing about Cocoa stands in your way. As a matter of fact, Xcode does have at least one other kind of window in which it shows some properties of a project:
That project settings sheet is really another window; macOS keeps it attached to the main window, but it is in fact an instance of NSWindow (or a subclass of NSWindow), no doubt with its own custom window controller that references the same project objects as the main window.
If you use the Cocoa NSDocument architecture, then a small amount of multi-window support is built-in: an NSDocument knows about its associated windows (via their window controllers). If you want to use the NSDocument architecture, you should read Document-Based App Programming Guide for Mac.
It is unclear what you are after. The traditional Mac UI has been one window per document - i.e. SDI with a single instance of the app running multiple windows - but there has always been the ability for any app to organise the content of that window as it sees fit, including showing multiple "documents" within one window - i.e MDI type UI.
Apps approach such "MDI" in different ways, e.g. some use panes (views) and others tabs. From macOS Sierra the standard NSWindow supports tabs, this system is (semi)automatic for standard document apps. Read Apple's NSWindow Automatic Window Tabbing section in the Sierra release notes for more details.
If you wish to use multiple panes - e.g. like Xcode - you just use views (NSView) and arrange them how you wish.
HTH
How do I add custom menu items to the context menu for files in Finder?
Unfortunately, most of the information out on the Internet and on Stack Overflow doesn't work in 10.6 or are too limited. Automator, for example, doesn't allow you to create items dynamically or create submenus.
I know it's still possible to do this sort of thing because Dropbox and FolderGlance both do similar things. Does anyone know how they implemented this?
Thanks.
For what it's worth, Dropbox now uses mach_star for code injection. Obviously this is a fragile solution. If you look through their version history, many of their updates are to fix finder integration.
In macOS 10.10+, Finder Sync Extensions can be used to add items to the Finder context menu. This is how modern versions of Dropbox and similar apps customize the right-click menu.
For those just seeking to use the functionality, not develop their own app extension, I've released a Mac app that allows for arbitrary customization of a Finder Sync Extension:
Service Station - Mac App Store
I downloaded FolderGlance and it appears to use an osax (Scripting Addition) bundle to inject code into the Finder process. This is definitely fragile and unsupported.
As far as I am aware the only legit way to add items to the Finder contextual menu is to create a Service, but that doesn't solve your problem.
Up to to the OS X 10.9.x only injecting code to Finder process via mach_inject was a solution (and even Dropbox did that).
However since 10.10 there are Finder plugins, which can customize context menus, add buttons to Toolbar and put overlays over file icons.
They used CFPlugIn to add their menu items.
More on it here:
http://developer.apple.com/library/ios/#documentation/CoreFoundation/Reference/CFPlugInRef/Reference/reference.html
I'm working to an application for OSX and I would to add a new menu item on the menu shown when you click on a dock icon.
The menu isn't for my application but it must appear for all running apps.
I've found only this doc http://cocoadevcentral.com/articles/000036.php but it adds to its own app.
My app will run on OSX 10.6 or superior
You can't do that with the public API. You need to inject code into the Dock. In 10.6, the standard way to inject the code is to use the OSAX loading trick, described in this blog post for that. Then you need to do Objective-C runtime hackery to replace the method, using method_exchangeImplementations.
Anyway it's a tricky process. But if you have the will, you can. SIMBL might (or might not) help you.
Is it possible to ask an OSX application which applescript commands it responds to, and if so, how?
You need to look at the Dictionary for an application to see all of the classes and commands the application supports. To get to an application's Dictionary in the the Applescript Editor go to File > Open Dictionary.... A list of all the applications that the OS knows supports Applescript will appear, but the OS won't catch them all so you can use the Browse button. If an application doesn't support Applescript, then it won't be selectable in the dialog window.
The caveat to this is that there are certain commands that an application is supposed to support but don't, or an application may only support the minimum requirements. These are all very, very simple like open, quit, etc. Your mileage may vary.
Using the Apple OS X Cocoa framework, how can I post a sheet (slide-down modal dialog) on the window of another process?
Edit: Clarified a bit:
My application is a Finder extension to do Subversion version control (http://scplugin.tigris.org/). Part of my application is a plug-in (a Contextual Menu Item for Finder); the bulk of my application, however, is in a separate daemon proces. For several reasons, we've chosen to put virtually all the code into the daemon; the plug-in only defines the menu itself, and Apple-Events over to the Daemon.
Sometimes, the daemon needs to prompt the user for further information. It can toss a window on-screen for this, but that's disruptive (randomly positioned), and it seems to me the work flow here is legitimately modal, for example "select a file, pick 'commit' from the menu, provide commit comments, do the operation."
Interprocess cooperation (such as passing a reference of some kind) is acceptable: both processes are mine, but I want to avoid binding the sheet's code into the primary process.
Really, it sounds like you're trying to have your inter-process communication happen at the view level, which isn't really how Cocoa generally works. Things will be much easier if you separate your layers a bit more than that.
Why don't you want to put the sheet code into the other process? It's view code, and view code is inherently process-specific. The right thing to do here is probably to add somewhat generic modal-sheet support to your plugin code, and an IPC call that your daemon can make to summon that code. Trying to ship view objects over to the remote process is going to be nightmarish if you can make it work at all.
You're fighting the frameworks with this approach.
You can't add a sheet to a window in another process, because you have at most only the most restricted access to the windows in the other process.
Please don't do this. Make the interaction nonmodal if at all possible. Especially in something like a commit, it's much nicer to be able to browse around your files while you're writing commit comments.
OS X does have window groups, but I don't think they can (easily) span applications.
Another thing to consider is that in OS X it's possible to have many Finder windows open on the same folder (unlike in OS 9). Even if you did have sufficient privileges/APIs to add a sheet to a Finder window, it's not like the modality of that window would prevent the user from being able to continue working with the files.
(My personal opinion as a long-time Mac user is that this kind of interaction would drive me right up the wall.)