mouseDown issue on custom view for a menubar app - objective-c

i'm trying to code a drag&drop menubar app. i used a custom view to access to the dropped file, and this works fine. now i would like to open the default menu when clicking on this view. i'm using this:
- (void)mouseDown:(NSEvent *)event {
[statusItem popUpStatusItemMenu:statusMenu];
}
now, the mouseDown works fine (trying with NSLog), but still i cannot access to statusItem and statusMenu.
this is in dropView.m, in dropView.h i got:
#interface dropView : NSView{
IBOutlet NSMenu *statusMenu;
NSStatusItem *statusItem;
}
no crash, no logsā€¦ any ideas? ty!
this is a bit more from the .m
- (void)awakeFromNib{
statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
[statusItem setMenu:statusMenu];
dropView *drop = [[dropView alloc] initWithFrame:NSMakeRect(0, 0, 24, 24)];
[statusItem setView:drop];
}

Add this to your .h file:
#property (strong, nonatomic) IBOutlet NSMenu *statusMenu;
#property (strong, nonatomic) NSStatusItem *statusItem;
Add this to your .m file:
#synthesize statusMenu, statusItem;
Then you'll access the properties with self.statusMenu and self.statusItem.

Related

NSMenu delegate does not trigger menuWillOpen

I've got an Interface Builder NSMenu-Object. I added my custom Class "StatusBarMenu".
The StatusBarMenu.h file looks like this:
#interface StatusBarMenu : NSMenu <NSMenuDelegate>
The StatusBarMenu.c file looks like this:
- (void)menuWillOpen:(NSMenu *)menu {
`NSLog(#"open");`
}
The Menu is assigned in the AppDelegate.c as follows:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.statusBar = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
self.statusBar.highlightMode = YES;
[self.statusBar setMenu:self.statusMenu];
}
And the AppDelegate.h:
#import <Cocoa/Cocoa.h>
#import "StatusBarMenu.h"
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (strong, nonatomic) NSStatusItem *statusBar;
#property (weak) IBOutlet StatusBarMenu *statusMenu;
The Menu opens, but menuWillOpen is not called.
Did i miss anything?
I appreciate any help!
Thanks.
You have to set the delegate, either in Interface Builder by a connection (statusMenu > delegate to AppDelegate) or in code in applicationDidFinishLaunching
self.statusMenu.delegate = self;

Objective-C NSPopover statusItem not opening

I'm having difficulty getting my NSPopover to function properly. The statusItem pops up in the status bar, and highlights on click, but the popover isn't displaying.
Here's the structure of my code.
#property (strong, nonatomic) NSStatusItem *statusItem;
#property (strong, nonatomic) NSEvent *popoverTransiencyMonitor;
#property (weak, nonatomic) IBOutlet NSPopover *popover;
#property (weak, nonatomic) IBOutlet NSView *popoverView;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
self.statusItem.highlightMode = YES;
[self.statusItem.image setTemplate:YES];
self.statusItem.action = #selector(itemClicked:);
}
-(void)itemClicked:(id)sender {
[[self popover] showRelativeToRect:[sender bounds] ofView:sender preferredEdge:NSMinYEdge];
if (self.popoverTransiencyMonitor == nil) {
self.popoverTransiencyMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:(NSLeftMouseDownMask | NSRightMouseDownMask | NSKeyUpMask) handler:^(NSEvent* event) {
[NSEvent removeMonitor:self.popoverTransiencyMonitor];
self.popoverTransiencyMonitor = nil;
[self.popover close];
}];
}
}
I got help from another person on StackOverflow, Gavin, and that help is located here. NSPopover transiency when popover is in status bar
I reached out to Gavin, and he managed to help me out by sending me his xCode project and it gave me some insight. But our code matches, mine doesn't work, and his does.
Any ideas?
This is a bit embarrassing, but it seems that the issue was that I created a project which uses Storyboards, and NSPopover wouldn't work with that for some reason.
Sorry for the clutter.

mac status bar application not working

I'm following this: http://lepture.com/en/2012/create-a-statusbar-app simple tutorial to get a Status Bar based Mac app working, I've referenced Apple's NSStatusItem class reference as well - And cannot figure out what I'm doing wrong?
It's just not working. My project uses ARC.
Here's FPAppDelete.h:
#import <Cocoa/Cocoa.h>
#interface FPAppDelegate : NSObject <NSApplicationDelegate>
#property (weak) IBOutlet NSMenu *statusMenu;
#property (strong, nonatomic) NSStatusItem *statusBar;
#end
Here's FPAppDelegate.m:
#import "FPAppDelegate.h"
#implementation FPAppDelegate
#synthesize statusBar = _statusBar;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}
- (void) awakeFromNib {
self.statusBar = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
self.statusBar.title = #"G";
self.statusBar.menu = self.statusMenu;
self.statusBar.highlightMode = YES;
}
#end
I'm not expecting this at all, but I get this when I run the app, with nothing in my Status Bar
It looks like you are willing to listen. So I'll show you quickly how to run a status application.
(1) Add NSMenu to the side bar (or whatever you call). (See the screenshot below.) It's up to you to keep or remove 3 generic menu items.
(2) Add the following instance variables under AppDelegate.h.
#interface AppDelegate : NSObject <NSApplicationDelegate> {
IBOutlet NSMenu *statusMenu;
NSStatusItem *statusItem;
NSImage *statusImage;
}
#property (assign) IBOutlet NSWindow *window;
#property (strong) NSMenuItem *menuItem1; // show application
I'll also add a property as an example.
The following code is for AppDelegate.m
#implementation AppDelegate
#synthesize menuItem1;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[self setMainStatus];
}
- (void)setMainStatus {
statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
statusImage = [NSImage imageNamed:#"statusImage"];
[statusItem setImage:statusImage];
[statusItem setMenu:statusMenu];
NSMutableString *menuname1 = [[NSMutableString alloc] initWithString:NSLocalizedString(#"statusMenuShowApplication", #"Show Application Window")];
menuItem1 = [[NSMenuItem alloc] initWithTitle:menuname1 action:#selector(statusApplicatinClicked:) keyEquivalent:#""];
[statusMenu addItem:menuItem1];
}
- (void)statusApplicatinClicked:(id)sender {
[self.window setIsVisible:YES];
}
#end
(3) Go back to Interface Builder and connect Status Menu to the NSMenu control you've added.
The setMainStatus method (or whatever you want to name) adds menu items to the status menu programatically. First, you need to create NSStatusbar, which takes NSImage. This NSImage is used to show an icon on the status menu. Next, add menu items and separators to the status menu (status Menu in my case). I have menuItem1 as a property so that the application could enable/disable it. That's just a quick example. You can add NSView to the status menu. If you want to add a separator, it can go as follows.
[statusMenu addItem:[NSMenuItem separatorItem]];
You don't need an application window to run a status menu application. You have to show the main application window for the first time if you are going to submit your status application to Apple's Mac App Store, though.
The status bar is the top-right part of your entire screen. It's where the date and time, Spotlight, etc live in the Menu Bar.
The screenshot you posted is of the title bar of your primary NSWindow.

How to update a menu item in a status menu on Objective-C

I'm a very beginner in Objective-C and in Mac development. I've searched this site for the answer I'm seeking, but due to a big ignorance I could not understand how this should be done.
The following piece of code implements a menu in Mac status bar, near the battery, wifi, etc icons on the top right of the screen.
If the user disconnects a device from the computer the method sayAdapterIsConnected is called with one boolean argument. Depending on that argument, one of the menu items, in this case the enabledOption, should get disabled. I mean, the menu item should be enabled or disabled.
This works only if the menu is closed. If the statusMenu is opened, it is not updated.
I know there is a way to update an open statusItem menu. Wifi status icon updates its networks while the menu is open.
#interface ENHeringAppDelegate : NSObject <NSApplicationDelegate> {
NSStatusItem * statusItem;
}
#property (weak) IBOutlet NSMenu *statusMenu;
#property (weak) IBOutlet NSMenuItem *enabledOption;
#end
#implementation ENHeringAppDelegate
- (void) awakeFromNib {
statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
[statusItem setMenu:_statusMenu];
[statusItem setTitle:#"TEST"];
[statusItem setHighlightMode:YES];
}
- (void)sayAdapterIsConnected:(bool)connected {
if (connected)
[self.enabledOption setEnabled:true];
else
[self.enabledOption setEnabled:false];
}
#end
A NSMenu isn't needed here. You also don't need the setMenu: call.
Here's a working example:
AppDelegate.h
#import <Cocoa/Cocoa.h>
#interface KBCAppDelegate : NSObject <NSApplicationDelegate> {
NSStatusItem *statusItem;
}
#property (assign) IBOutlet NSWindow *window;
- (IBAction)update:(id)sender;
#end
AppDelegate.m
#import "AppDelegate.h"
#implementation KBCAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
[statusItem setTitle:#"TEST"];
[statusItem setHighlightMode:YES];
[statusItem setEnabled:YES];
[statusItem setTarget:self];
}
- (IBAction)update:(id)sender {
if (!statusItem.isEnabled) {
[statusItem setEnabled:true];
} else {
[statusItem setEnabled:false];
}
}
#end
That's all you need to do. (I made update: an IBAction, but a void function like what you show would work too)
P.S.
Make us nitpickers happy and always use braces in your if/then statements, even if there is only one line. :)

How to change NSMenuItem Title (Login to Logout)

Im surprised that this hasn't already been asked:
But how does one go about changing the NSMenuItem title in a NSStatusBar menu. When a user logs in I want the menu item to say logout. I have tried creating an outlet to modify my NSMenuItem as a would a label or something.
AppDelegate.h
#property (retain) IBOutlet NSMenuItem *loginItem;
AppDelegate.m
[loginItem setTitle:#"Logout"];
But that didnt work.
The only thing that I was able to do was delete the old NSMenuItem, then add a new one, but it would just add it to the bottom. Is the only way to do this to remove every menu item then re-add them?? That seems very inefficient.
The method you describe should work, though, in general, keeping IBOutlets for all your menu items can be tedious. (If your solution isn't working, make sure the IBOutlet is actually connected in the nib file, and make sure that you're setting the title at an appropriate time. If you're trying to set it in your controller's init method, for example, that's too early on, and the outlets haven't yet been connected up: move the method to awakeFromNib or similar.
A better approach in the long run is to use the <NSMenuDelegate> protocol and NSMenuValidation (informal) protocol to update menu items dynamically (and lazily).
For example, define your controller class like the following:
#interface MDAppDelegate : NSObject <NSApplicationDelegate, NSMenuDelegate>
#property (strong) NSStatusItem *statusItem;
#property (weak) IBOutlet NSWindow *window;
#property (weak) IBOutlet NSMenu *statusItemMenu;
#property (weak) IBOutlet NSMenuItem *toggleLoginLogoutMenuItem;
#property (weak) IBOutlet NSTextField *statusField;
#property (weak) IBOutlet NSTextField *progressField;
#property (weak) IBOutlet NSProgressIndicator *progressIndicator;
#property (assign) BOOL loggedIn;
- (IBAction)toggleLoginLogout:(id)sender;
#end
In the nib file, the delegate outlet of the statusItemMenu is set to the MDAppDelegate controller class. That assures that the MDAppDelegate class is in the responder chain and allow it to work with validating the menu items.
Then you could implement your .m like the following:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
_statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
_statusItem.menu = _statusItemMenu;
_statusItem.title = NSLocalizedString(#"NSStatusItem", #"");
[self updateLoggedInStatus];
}
- (void)updateLoggedInStatus {
[self.statusField setStringValue:(self.loggedIn ? #"Logged in" : #"Logged out")];
}
- (IBAction)toggleLoginLogout:(id)sender {
[self performSelector:#selector(finishFakeLoginLogout:)
withObject:nil afterDelay:2.0];
}
- (void)finishFakeLoginLogout:(id)sender {
self.loggedIn = !self.loggedIn;
[self updateLoggedInStatus];
}
- (void)menuNeedsUpdate:(NSMenu *)menu {
#if MD_DEBUG
NSLog(#"[%# %#]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
#endif
}
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
#if MD_DEBUG
NSLog(#"[%# %#]", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
#endif
SEL action = menuItem.action;
if (action == #selector(toggleLoginLogout:)) {
[menuItem setTitle:(self.loggedIn ? #"Logout" :#"Login")];
}
return YES;
}
Sample project: http://github.com/NSGod/NSStatusBarFinagler
You don't need to connect your menu item just try this..
NSMenuItem *menuItem = (NSMenuItem*) sender;
NSString *menuString = menuItem.title;
if ([menuString isEqualToString:#"Login"])
{
[menuItem setTitle:#"LogOut"];
}
NSMenuItem menuItem = (NSMenuItem) sender;
this line automatically collect the menu items in your app.