Last Updated on Thursday, August 8, 2002 (8:52 PM)
Maintained By Duane Murphy
See About Extendamac
"Extendamac is a community of Macintosh developers organized to document and distribute best known practices for extending the Mac OS and improving the Mac OS experience."
How do I write an OS X System Menu?
?
How do I write an OS X Dockling?
Docklings are no longer supported in Mac OS X. However, applications can modify their icon and menu shown in the dock, so a normal application can be made that will fulfill most needs. You only need to get the application launched at startup. See Customizing Your Application Dock Tile [GW]
If you feel that you really need to write a dockling, then the article Creating docklings on Mac OS X 10.0.4 from StepWise may prove useful. [WF]
There are a couple of reasons for wanting to a do a dockling over an application. Docklings are loaded automatically at login. You can arrange for your application to do the same, however there are differences. A dockling does not have a Quit and Hide menu item that all applications have. Alas, there is currently no way to disable these menu items.
LoginWindowCheck.c is a procedure for adding and removing an application from the login window's list of startup items. [GLW]
Here's the "unofficial" code to add an application to the dock's preferences. It won't actually update the dock until the next time it starts up (login?). Note that Apple might change how this preference is stored at any time and that this code may break if they do. Use at your own risk.
Hey, OS X doesn't have traps and there's all this memory protection stuff. How do I get my code to run inside of other applications?
?
I heard about this thing called libPatch. Can I use that to get into other applications?
libPatch was an early effort to allow code to be executed inside of other applications. It is now deprecated and no longer supported. You should use [ application extension? ] instead.
How do I get a window to float over all the other window like DragThing?
OS X has the utility window class and the overlay window class. There are also window groups and layers. See MacWindows.h
for a starting point to learn more.
In OS X, you can create a transparent window that covers the entire screen. This makes it appear that you are drawing over the entire screen. See overlay windows in MacWindows.h
.
How do I get the list of all the windows in OS X?
There are a couple of answers to this question.
If you are working in OS X 10.1.x or newer you may have to use some private functions. In 10.2 Apple is introducing Accessibility APIs that may provide more access. You need to use private functions within the CoreGraphics framework. More specifically, these:
typedef UInt32 CGSConnectionRef;
typedef UInt32 CGSWindowRef;
CG_EXTERN CGError CGSGetConnectionIDForPSN(UInt32 inParam1,
ProcessSerialNumber* inPSN, CGSConnectionRef* outConnectionRef);
CG_EXTERN CGError CGSGetOnScreenWindowCount(CGSConnectionRef
inCurrentConnectionRef, CGSConnectionRef inTargetConnectionRef, UInt32*
outWindowCount);
CG_EXTERN CGError CGSGetOnScreenWindowList(CGSConnectionRef
inCurrentConnectionRef, CGSConnectionRef inTargetConnectionRef, UInt32
inMaxWindowRefs, CGSWindowRef* outWindowRefList, UInt32*
outWindowRefListCount);
Then you'll want to walk the process list and get the list of windows for each process. Code like this will do that:
CGError err = 0;
UInt32 count = 0;
UInt32 connectionID = 0;
ProcessSerialNumber psn = {kNoProcess, kNoProcess};
UInt32 myConnectionID = 0;
ProcessSerialNumber myPSN = {kNoProcess, kNoProcess};
// get our connection id. From looking at other hacks
// I believe you can do this part another way.
GetCurrentProcess(&myPSN);
err = CGSGetConnectionIDForPSN(0, &myPSN, &myConnectionID);
// walk the process list
err = GetNextProcess(&psn);
while( err == noErr ) {
err = CGSGetConnectionIDForPSN(0, &psn, &connectionID);
if( err == noErr ) {
err = CGSGetOnScreenWindowCount(
myConnectionID, connectionID, &count);
if( (err == noErr) && (count > 0) ) {
UInt32* ids = (UInt32*)calloc(count, sizeof(UInt32));
UInt32 actualIDs = 0;
UInt32 i = 0;
err = CGSGetOnScreenWindowList(m
yConnectionID, connectionID, count, ids, &actualIDs);
for(i = 0; i < actualIDs; i++) {
// do something with the actualIDs[I]
}
free(ids);
}
}
err = GetNextProcess(&psn);
}
Once you have the window ID you can get information about that window. [AF]
Private APIs! Isn't that dangerous? What does Apple have to say about this?
Yep, they are dangerous. There is a risk that Apple may change private APIs at any time. This is the risk you take and the users of your application. You must do your best to code defensively to prevent a bad experience for the user; they're the reason we're here, remember.
Apple's statement on using private APIs is simple. Don'ft do it. They are unsupported and unauthorized. Your application could break at any time.
It should be made clear that some information presented by extendamac will use unpublished, undocumented, private APIs. Use this information at your own risk. In order to achieve some functionality, using these APIs may be necessary. We will always encourage Apple to provide sanctioned APIs for our needs. When and if that happens, the information on extendamac will be updated.
What about these Accessibility APIs?
Basically, Mac OS X 10.2 (Jaguar) will provide an Accessibility API which is meant to allow the creation of software to improve the accessibility of the system to users with disabilities. However, there's nothing stopping you from using it either. The API allows you to ask for attributes of accessible objects in the user interface; one such accessible object is the application, and one of its attributes is its list of children. The children of the application are its menubar and its visible windows, so this would give you a way to get all of the visible windows of an application. [ES]
How do I write a contextual menu that shows up in the Finder?
You want to write a contextual menu plugin. See SampleCMPlugin for sample code. [AF]
How do I make my application's icon not show up in the dock?
Add LSUIElement = 1
to your Info.plist
. With this you can still display UI, but your menu bar and dock icon will not show. [LY]
There is also an LSBackgroundOnly
flag for processes that truly have no UI. It should be noted that the LSBackgroundOnly
applications are treated as daemons and are exited using SIG_QUIT
(and friends including SIG_KILL
) instead of the usual AEQuit
method. [LY]
How do I catch shortcut keys globally?
You want to use the hot keys API found in carbon. See CarbonEvents.h
and search for RegisterEventHotKey
. [AF]
Hot key support is undocumented in Cocoa. You can't just use Carbon Event handlers in Cocoa (registering them works, but they're never invoked). However, you can examine events as they get delivered to NSApplication
by overriding -[NSApplication sendEvent:]
. Sample code can be found in HotKeys.dmg [NR]
The following individuals have contributed to the information contained in this FAQ.
[AF] | Andy Finnell |
[ES] | Eric Schlegel |
[GLW] | Gary L. Wade |
[GW] | George Warner |
[DM] | Duane Murphy |
[NR] | Nicholas Riley |
[WF] | Jonathan 'Wolf' Rentzsch |