Contextual Menu Modules
Volume Number: 14
Issue Number: 2
Column Tag: Toolbox Techniques
by Steve Sheets
By creating Contextual Menu Extension Modules for Mac OS
8, you can extend the behavior of all applications
A New type of Extension
The Contextual Menu (CM) Manager was introduced with Mac OS 8.0. Using this
manager, developers now can provide contextual menus in their programs. When a
user clicks some data while holding the control key down, a list of data specific
commands can appear. For example, the Finder uses this API to display various
commands (Open, Move to Trash, Get Info, Duplicate) when files & folders are
control-clicked. As mentioned in last month's article, the commands that are listed
come from two sources; the program and CM extension modules. This month's article
will demonstrate how to create the example plug-in "CaseCharm".
At any point in a program that uses the CM API where "ContextualMenuSelect" is
called, the programmer can provide 2 important pieces of information. First, he can
provide the list of the commands to be displayed. Secondly, he can provide the data that
is currently selected. CM extensions, also known as plug-ins, can use this data to
decide what additional commands also can be added to the menu. If the user selects one
of the commands that comes from the plug-in instead of from the program, the plug-in
takes care of that action. The calling program is not aware that anything was selected;
it just functions as if the user failed to select an item from the menu. Except for being
able to look at the selected data, the plug-ins are transparent to the calling program,
and the calling program is not aware of the plug-ins.
So what are CM extensions? They are PowerPC code fragments (that is, shared
libraries) using the SOM Object model. Because of this, plug-ins can only run on
PowerPC Macintoshes. The API is standard on Mac OS 8.0 computers, but it also can be
installed on System 7.x machines. Do not assume that all the Mac OS 8.0 APIs are
available for a contextual menu. Though uncommon, contextual menus can be used on a
pre-8.0 machine.
CM plug-in files must have the file type of 'cmpi'. If they have the creator of 'cmnu',
they will display the generic CM icon. The extension file must reside in the "Contextual
Menu Items" folder in the System Folder. On Mac OS 8.0, dragging the extension onto
the System Folder will automatically move the file to the correct location. On pre-Mac
OS 8.0, you must drag the files manually. Once they are in the correct location, the
System must be rebooted for the plug-in to be installed.
Being SOM objects, CM plug-ins are object-oriented subclasses of the super class
AbstractCMPlugin. AbstractCMPlugin object has several calls that must be overridden
for the extension to work. While you can create CM plug-ins that do not look at the
selected data, but just provide some function, this is not a recommended. There are
plenty of other way to provide commands in the Macintosh. Apple recommends that
third party developers work on CM plug-ins that are data sensitive.
While the Contextual Menu Manager passes the selected data to the plug-in, the
plug-in can not modify this data. At most, it can make a copy of the data, modify the
copy, and then return the data by placing it in the Clipboard. The example project
CaseCharm, discussed below, takes text data and shifts it to either upper or lower case.
For example, in a word processor, a user would select a word, control-click that
word, select the CaseCharm command, then paste the content of the Clipboard (the
word all in upper or lower case) back into the word processor. This passing of
modified data using the Clipboard is a common function of CM plug-ins.
Creating a Module Project
While a CM project can be created from scratch, the easiest way to set up one is to take
an existing CM sample project and modify it for your needs. It is to easy to incorrectly
set one of the required preferences in the project. In the CM Manager SDK (available
from Developer CDs and websites), Apple provides a good sample program to start
with. The example used in this article is based on Apple's sample code.
You must change a couple of project preferences when creating a new CM plug-in. For
this project you must first change the PPC Target file name to "CaseCharm". Next, the
PPC Linker Entry Point for Initialization must be changed to a new name. While it can
be anything, the common usage is XXXInitialize, XXX is the name of the CM plug-in, in
this case "CaseCharmInitialize".
Then you must modify the source files to match the name changes. The .cp, .h & .r files
should be renamed to match the CM plug-in name. In this case, "CaseCharm.h",
CaseCharm.cp" and "CaseCharm.r". Following sections will explain the changes within
these files. In addition to these source files, the sample project includes the
"UContextualMenuTools.cp" file. This code provides many useful routines to handle
functions common to all CM plug-ins.
Additionally, various libraries must be linked in the project. These include
AbstractCMPlugin, InterfaceLib, MSL RuntimePPC.Lib and SOMObjects(tm) for Mac
OS. The file names for some of these libraries may be different for different
development environments. The AppearanceLib library is required only if the CM
plug-in uses the Appearance Manager.
Once all the changes are done, compile and link the code. As mentioned above, the
resulting shared library must be dragged to the "Contextual Menu Items" folder and the
Mac rebooted to test the code.
Adding Resources
A CM plug-in does not require much in the area of resources. Like all code fragments,
the 'cfrg' resource is required. The fields containing the code fragment name & help
information (in this case the strings "CaseCharm" and "A Contextual Menu Plugin to
change the case of selected text") should be changed. It is always a good idea to include
version information ('vers' resources) with any code.
Listing 1
CaseCharm.r
Typical resources for a Contextual Menu plug-in, in this case
CaseCharm.
#define UseExtendedCFRGTemplate 1
#include "SysTypes.r
#include "CodeFragmentTypes.r
/* Code Fragment Info */
resource 'cfrg' (0) {
{ /* array memberArray: 4 elements */
extendedEntry {
kPowerPC,
kFullLib,
kNoVersionNum,
kNoVersionNum,
kDefaultStackSize,
kNoAppSubFolder,
kIsLib,
kOnDiskFlat,
kZeroOffset,
kSegIDZero,
"CaseCharm", /* Changed for each Plug-In */
kFragSOMClassLibrary,
"AbstractCMPlugin",
"",
"",
"A Contextual Menu Plugin to change the case of
"selected text." /* Changed for each Plug-In */
}
}
/* Version Info */
1, 0, final, 0, verUS, "1.0", "Mageware, 1997
1, 0, final, 0, verUS, "1.0", "CaseCharm 1.0
Methods and Methods
As will be stated over and over, a CM plug-in is a SOM object. In this example,
CaseCharm is a subclass of class AbstractCMPlugin. This new class overrides 4
methods of AbstractCMPlugin. CaseCharm also requires one special initialization
routine for SOM to identify it. All CM plug-ins override these 4 methods (and provide
an Initialization routine), so the header code is generally identical. Listing 2 shows the
CaseCharm.h file. The name of the new subclass of AbstractCMPlugin must match the
name given in the resource file (in this case, "CaseCharm").
Listing 2
CaseCharm.h
Typical header file for a Contextual Menu plug-in, in this case
CaseCharm.