NSMenuExtra tutorial Part 1 of 2
NSMenuExtra tutorial Part 1 of 2
- Subject: NSMenuExtra tutorial Part 1 of 2
- From: Rustam Muginov <email@hidden>
- Date: Tue, 23 Sep 2003 12:24:03 +0400
Hello, Cocoa Developers.
I have created a small tutorial about NSMenuExtra and would like to share my
experience. Probably someone would found it useful.
The tutorial itself is RTF file, but I am posting it as a plain text here.
-----------------
Small tutorial on building MenuExtra
What should you understand before creating MenuExtra.
1. This is the software which is using private, undocumented MacOS X
API. Where are no any guarantees what this software would work in the
following major MacOS X versions.
2. In the MacOS X 10.2, Apple made some effort to prevent third-party
MenuExtra being loaded. Under MacOS 10.2, you would need to use Menu Extra
Enabler from Unsanity (
http://www.unsanity.com/download.php?product=mee) or
MenuCracker from james_007_bond
(
http://sourceforge.net/projects/menucracker).
3. The NSMenuExtra class is the subclass of NSStatusItem, which is the
recommended way of putting custom menus to the right side of the menu bar.
Although not as convinient and powerful as NSMenuExtra (you can not
control-drag to rearrange or remove NSStatusItem, you have to have a running
application to keep it in the menu bar, e.t.c.), it is still documented (at
least partialy) and recommended way. Perharbs you should consider if
NSStatusItem is sufficient for your requirements first. A nice tutorial is
available at Cocoa Dev Central
(
http://cocoadevcentral.com/articles/000052.php).
Available implementations of NSMenuExtra
Where are several implementations available, with source code. They are:
1. Application Menu Switcher by Frank Vercruesse
(
http://sourceforge.net/projects/x-asm)
2. ClassicSpy by Konstantin Anoshkin
(
http://www.anoshkin.net/show.php?products)
3. MenuMeters by Alex Harper
(
http://www.ragingmenace.com/software/menumeters/index.html)
They are very valuable examples, but personaly i've found they are a bit
too complex for the beginner. Another side, they are all distributed under
GNU License, making it impossible for shareware/commercial developer to use
their source code.
You will definitly worth to look at their source code later, to learn
more about the NSMenuExtra functionality.
Reverse-engineering the API.
The NSMenuExtra class resides in the SustemUIPlugin private framework.
Objective-C keeps plenty of information about class names, inheritance,
methods, e.t.c., so it is possible to get this information from the compiled
binary. To obtain this framework API, we would use very useful class-dumb
utility by Steve Nygard. It is available at
(
http://www.omnigroup.com/~nygard/Projects/index.html) or
(
http://homepage.mac.com/nygard/Projects/). Download the archive and unpack
it. The class-dump is the command-line utility, so we would run it in
terminal.
If you put the "class-dump" binary inside the /Applications folder, then
the command line would be
"/Applications/class-dump -e
/System/Library/PrivateFrameworks/SystemUIPlugin.framework/Versions/A/System
UIPlugin > SystemUIPlugin.h"
Run this command, and check inside your home folder. You would find the
"SystemUIPlugin.h" file in it.
We need to do some editing before it would be compilable, Open it in
Project Builder and look at it nice content. We would need to do some
editing before this code would be compilable though.
First, add the #import <AppKit/AppKit.h> just under the comments. Then,
correct the following:
1. Remove the "?" sign in the struct declarations in the NSMenuExtra and
NSDockExtra interfaces
2. Replace the "expanded" struct _NSRect types in the "initWithFrame" and
"drawRect" methods of NSMenuExtraView class. They should be
- initWithFrame:(NSRect)fp12 menuExtra:fp28;
- (void)drawRect:(NSRect)fp12;
Now we have the API to the NSMenuExtra (and the whole SystemUIPlugin)
private framework.
Creating the project.
Create new ProjectBuilder project, using Cocoa Bundle template. Name it,
for example, "Sample". We need to tune some parameters, so select the
"Targets" tab and click the "Sample" target.
1. In the Settings/Expert View, change the "WRAPPER_EXTENSION" from "bundle"
to "menu"
2 . In the "Info.plist entries/Basic Information", set Identifier to
something like "com.MyCompany.SampleMenu"
3. In the "Info.plist entries/Cocoa Specific", set the Principal class to
"SampleMenuExtra.
We have done with project settings, now click "Files" tab.
Add the "SystemUIPlugin.framework", either by drag-n-dropping it from
Finder, or via "Project/Add FrameWorks..." menu.
Remove the "main.c" file from the project.
Copy the "SystemUIPlugin.h" file from your home folder to the project
folder, and add it to Classes group.
Creating source files.
Our project would have two classes.
Create the new class, from the "Objective-C class" template. Name it
"SampleMenuExtra". In the header, import the "SystemUIPlugin.h" and make our
class subclass of the NSMenuExtra. Add the "@class SampleMenuExtraView;"
forward declaration.
We will add only two instance variable to our class -
NSMenu *theMenu;
SampleMenuExtraView *theView;
the .m file
Import two interfaces - "SampleMenuExtra.h" and "SampleMenuExtraView.h" (we
will make it later). We gonna implement three methods here.
- (id)initWithBundle:(NSBundle *)bundle
first, usual things
self = [super initWithBundle:bundle];
if( self == nil )
return nil;
then we gonna create and set the MenuExtraView
theView = [[SampleMenuExtraView alloc] initWithFrame:[[self view]
frame] menuExtra:self];
[self setView:theView];
and at last prepare "dummy" menu, without any actions
theMenu = [[NSMenu alloc] initWithTitle: @""];
[theMenu setAutoenablesItems: NO];
[theMenu addItemWithTitle: @"1" action: nil keyEquivalent: @""];
[theMenu addItemWithTitle: @"2" action: nil keyEquivalent: @""];
[theMenu addItemWithTitle: @"3" action: nil keyEquivalent: @""];
Finish the method with usual return self;
- (void)dealloc
this is quite familiar
[theMenu release];
[theView release];
[super dealloc];
- (NSMenu *)menu
its just an accessor, called by system then our menu need to be drawn.
Simply
return theMenu;
Now create another class, SampleMenuExtraView, again using the
Objective-C class template.
In the header: #import "SystemUIPlugin.h"
Make class subclass of NSMenuExtraView.
In the source file, we gonna implement single method
- (void)drawRect:(NSRect)rect
This method would be called then our menu extra have to draw its "title
picture", providing the rectangle. We would not make someting very complex
and would just draw a circle, sligtly smaller then the rect itself.
[[NSColor purpleColor] set];
NSRect smallerRect = NSInsetRect( rect, 4.0, 4.0 );
[ [NSBezierPath bezierPathWithOvalInRect: smallerRect] fill];
Thats all class implementation!
Build the project, you would got a link warning, just ignore it so far.
Go to your build folder, you would see the "Sample.menu" bundle in it.
Double-click it and enjoy.
------
Continued in part 2
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.