NSStatusItem for local IP Address

Hello everyone,

I’m looking for some guidance on how to proceed, as this item I’m trying to work on is really driving me nuts.

I had posted a while ago about trying to make a menulet that would show the local IP address of the computer. I’m going to be deploying this to ~1200 computers to help with our tech support needs via ard/vnc. We’ve found that most of our employees cannot be bothered to find their IP address, so we want to have it displayed in an easy-to-find area.

So a while ago I started to follow some tutorials (http://www.mactech.com/articles/mactech/Vol.22/22.02/Menulet/) on how to make a menulet. I am by no means an ObjC user, but I know enough to follow along. I was able to get the example working with no problems under 10.4 and 10.5.

Now i’m working on a 10.6 machine running XCode 3.2.1 and I cannot get these examples to work at all. I was able to get it to set the status item, but I cannot get it to fire off the code that will actually check and do an update. I eventually want to make it with no user interaction and I’m going to wrap some command line code to pull the currently active card’s address, but I can’t even get it to pull the “test” string I have right now.

I guess what I’m trying to figure out now is, is it worth it to try and continue with this menulet ( and can I make it so that it will run on 10.4, 10.5 and 10.6 with the same code) or should I be looking to a different solution? Our windows guy has the ability to either embed the IP address on the desktop or make it a tool tip when hovering over the main hard drive, but I’m not sure if that’s something that is even possible.

If someone can help me out with the code for the menulet, that would be great, but any advice would be welcome. I want to learn more about apple programming, but, of course, I was thrown into this by my boss so I have to make it first and understand it later, so I apologize for my newbie-ness with all of this.

IPMenulet.h

[code]#import <Cocoa/Cocoa.h>

@interface IPMenulet : NSObject {
NSStatusItem *statusItem;
}

-(IBAction)updateIpAddress:(id)sender;

@end[/code]
IPMenulet.m

[code]#import “IPMenulet.h”

@implementation IPMenulet

  • (void) awakeFromNib{

    //Create the NSStatusBar and set its length
    statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength] retain];

    [statusItem setHighlightMode:NO];
    [statusItem setTitle:[NSString
    stringWithString:@“Updating…”]];
    [statusItem setEnabled:YES];
    [statusItem setToolTip:@“Your Current IP Address”];
    }

  • (void) dealloc {
    [statusItem release];
    [super dealloc];
    }

-(IBAction)updateIpAddress:(id)sender
{
[statusItem setTitle:
[NSString stringWithString:@“test”]];
}
@end[/code]
Thanks for any help anyone can give.

Hi,

this is the easiest method to display the local IP address

-(IBAction)updateIpAddress:(id)sender { NSAppleScript *scriptObject = [[NSAppleScript alloc] initWithSource:@"get IPv4 address of (system info)"]; NSString *ipAddress = [[scriptObject executeAndReturnError:nil] stringValue]; NSAttributedString *itemTitle = [[NSAttributedString alloc] initWithString: ipAddress attributes: nil]; [statusItem setAttributedTitle: itemTitle]; [itemTitle release]; [scriptObject release]; }
Edit
PS: or a solution without AppleScript call (requires at least OS 10.5)

[code]-(IBAction)updateIpAddress:(id)sender
{
NSString *ipv4Address = nil;
NSArray *addresses = [[NSHost currentHost] addresses];
for (NSString *anAddress in addresses) {
if (![anAddress hasPrefix:@“127”] && [[anAddress componentsSeparatedByString:@“.”] count] == 4) {
ipv4Address = anAddress;
break;
}
}
NSAttributedString *itemTitle;
itemTitle = [[NSAttributedString alloc] initWithString: (ipv4Address) ? ipv4Address : @“IPv4 address not available” attributes: nil];

[statusItem setAttributedTitle: itemTitle]; 
[itemTitle release];

}[/code]

Stefan, you are great. I have it working now so if I click on the words that first appear *Updating", it gets the IP address.

Is there a way, however, to get it to fire off that function when the program first loads?

this awakeFormNib method is sufficient.
Keep the dealloc method and delete the whole updateIpAddress: method, also in .h file

[code]-(void)awakeFromNib
{
NSStatusBar *bar = [NSStatusBar systemStatusBar];
NSString *string;

NSArray *addresses = [[NSHost currentHost] addresses];
for (NSString *anAddress in addresses) {
	if (![anAddress hasPrefix:@"127"] && [[anAddress componentsSeparatedByString:@"."] count] == 4) {
		string = anAddress;
		break;
	}
}
NSAttributedString  *itemTitle = [[NSAttributedString alloc] initWithString: (string) ? string : @"IPv4 address not available" attributes: nil];
statusItem = [[bar statusItemWithLength: NSVariableStatusItemLength] retain];
[statusItem setMenu:menu];
[statusItem setAttributedTitle: itemTitle];
[itemTitle release];

}[/code]

Perfect, thank you so much.

Now I just have to figure out how to make it refresh after a certain amount of time. The code from the tutorial seems to make the program hang.

No problem

.h file

[code]#import <Cocoa/Cocoa.h>

@interface IPMenulet : NSObject
{
NSStatusItem *statusItem;
IBOutlet NSMenu *menu;
NSTimer *updateTimer;
}

  • (void)updateIpAddress:(NSTimer *)timer;

@end[/code]
.m file

[code]#import “IPMenulet.h”

@implementation IPMenulet

-(void)awakeFromNib
{
NSStatusBar *bar = [NSStatusBar systemStatusBar];
statusItem = [[bar statusItemWithLength: NSVariableStatusItemLength] retain];
[statusItem setMenu:menu];
updateTimer = [NSTimer scheduledTimerWithTimeInterval:300.0
target:self
selector:@selector(updateIpAddress:)
userInfo:nil
repeats:YES];
[updateTimer fire];

}

  • (void)updateIpAddress:(NSTimer *)timer
    {
    NSString *string;

    NSArray *addresses = [[NSHost currentHost] addresses];
    for (NSString *anAddress in addresses) {
    if (![anAddress hasPrefix:@“127”] && [[anAddress componentsSeparatedByString:@“.”] count] == 4) {
    string = anAddress;
    break;
    }
    }
    NSAttributedString *itemTitle = [[NSAttributedString alloc] initWithString: (string) ? string : @“IPv4 address not available” attributes: nil];
    [statusItem setAttributedTitle: itemTitle];
    [itemTitle release];
    }

-(void)dealloc
{
[statusItem release];
[super dealloc];
}

@end[/code]
the interval is specified in seconds, in this example 300.0 (= 5 min). The .0 suffix defines the value as float/double, which is expected

Note: the NSMenu IBOutlet menu is a custom menu which contains at least a Quit item

Hi all,
I have created a version of this (above) to show the Name of the mac.

All works fine, but I can not re arrange the Menulet in the title bar to a new position??

The Menulet needs to work on 10.5 +

Any one k ow how to do this??

Hi Mark,

as far as I know custom menulets can’t be moved at all in the menu bar.
Apple’s menulets belong to SystemUIServer which has no public API

Hi Stefan,

Your right, I finally realised that I would have to use the private API, If I wanted this, but at this stage its not worth the hassle.

Many thanks.