EDIT: This is a nice ready-made menubar application here (github source) by this answer.
I was wondering how to make a menubar application, what are the requirements for that to do so?
I saw a simple application for the menubar was to open links using your browser, I want to create something similar to that.
This is the application I like to make similar.
NSStatusItem is what you are looking for. Also add LSUIElement with string value of 1 to your Info.plist to hide it from Dock.
I've found Codebox's Popup to be a great starting point. It is ripe for forking on Github.
Though it works nicely, they do note on their site...
P. S. In Lion, Apple is adding a new class for popovers like in iOS.
So, after OS X 10.7 is released, you would better to rely on native
Cocoa classes where it is possible. In other cases, the Popup project
should still be usable.
BitBar is an application on GitHub that can "Put anything in your Mac OS X menu bar".
It runs shell or other executable scripts (which it calls Plugins - see the many examples in the plugins repo) and displays the results in the menu bar. You can write your own plugin and have it run simply by adding it to the 'Plugins folder'. As well as displaying information, it can also run pre-defined bash scripts interactively from the plugin menus you define.
Since I first posted this answer it's popularity has exploded (52 contributors currently) and there is now even a distributable version with which you can package your own plugins.
A very simple (non-interactive) example to show live Bitcoin price:
As Apple added NSStatusBarButton property to NSStatusItem in Yosemite, we can implement menubar app a lot simpler. I just created a sample project on github.
https://github.com/taichino/PopupTest
FlyCut is another nice open source application that does this. (MIT licensed.) Very handy too, I use it several times a day.
Here's some code that seems like it may be relevant:
// Flycut/AppController.h
IBOutlet NSMenu *jcMenu;
// Flycut/AppController.m
statusItem = [[[NSStatusBar systemStatusBar]
statusItemWithLength:NSVariableStatusItemLength] retain];
[statusItem setHighlightMode:YES];
if ( [[DBUserDefaults standardUserDefaults] integerForKey:#"menuIcon"] == 1 ) {
[statusItem setTitle:[NSString stringWithFormat:#"%C",0x2704]];
} else if ( [[DBUserDefaults standardUserDefaults] integerForKey:#"menuIcon"] == 2 ) {
[statusItem setTitle:[NSString stringWithFormat:#"%C",0x2702]];
} else {
[statusItem setImage:[NSImage imageNamed:#"com.generalarcade.flycut.16.png"]];
}
[statusItem setMenu:jcMenu];
[statusItem setEnabled:YES];
Mail Notifr is another open source Menubar app. It helped me a bunch, especially when I needed to figure out how to implement the open on login. Also available on the App Store.
Related
I encountered a very strange problem which I can't solve by myself. I have several UI elements embedded in a NSWindow running as NSBorderlessWindowMask. There are 2 NSSlider, 3 NSButton, a NSComboBox and a NSColorWell.
The application builds for target 10.7 and has sandboxing enabled.
On my development machine every element works as intended. The NSComboBox has a working DataSource and Delegate. The NSColorWell does work too. When I click into the NSComboBox, I can type a text into it. And the NSColorWell opens a color selection.
The moment I hand my app to my beta-tester, the NSComboBox and the NSColorWell can't be edited. This means, that I can add elements to the DataSource of the NSComboBox (via an import) and they may be selected in the dropdown menu, but I can't click into the NSComboBoxCell and write a text. Also no color selection opens when I click the NSColorWell.
I have no clue at all what could cause this behavior. Every element is hooked up correctly and I run the same binary as my beta-tester. The systems both run Mountain Lion in its latest version. I tried creating a NSButton for the beta-tester which runs following methods on the NSComboBox:
[self.nameCB reloadData];
[self.nameCB setEnabled:YES];
[self.nameCB setEditable:YES];
[self.nameCB setNeedsDisplay:YES];
[self.nameCB setFrame:self.nameCB.frame];
[self.nameCB becomeFirstResponder];
[self.nameCB setSelectable:YES];
None helped. I have no clue how to "debug" this behavior. Do you have any suggestions?
Edit: I was able to break it down a bit. When I remove the line
[self.window setStyleMask:NSBorderlessWindowMask];
It works. But I want to get a nice look from removing the titlebar, so it only helps a bit.
As I already edited into my question I found out that this problem is caused by the NSBorderlessWindowMask style on my main NSWindow. I found no other way around it than subclassing NSWindow.
I used this example as a guide. It also works if you just extract the CustomWindow class from the project and add it to your project. Then just set the class of your window in IB to the CustomWindow
I still don't know what caused this problem. If anybody has an idea feel free to leave another answer below please.
When I was using Chrome to download something in Lion, a badge with downloading progress which dynamically updates itself is shown on my dock.
How may one go about achieving that?
I think you are looking for this piece of code:
[[[NSApplication sharedApplication] dockTile] setBadgeLabel:#"My String"];
Here you can find all the information you need (it's the NSDockTile Class Reference).
I have a question, I do some iphone application and now I want to do a little mac application.
From a clean application I add a button on MainMenu xib, than I add a NSViewController to MainMenu (from IB) with one Action.
I create a new NSViewController (FirstViewController) with a nib file and a button.
Now I want only to create a function to push FirstController from MainMenu and a simple function to push MainMenu from FirstController.
something like this
ViewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController: ViewController animated:YES];
How can I do it???
I think you're trying to bring an iOS-style interface to MacOS X, and that won't work in many cases. The MacOS X user interface is very different from that of iOS.
iOS apps are limited to a single (and often small) window, and users generally do one thing at a time. The navigation interface standardizes the way that users drill down through different parts of a task so that the journey is predictable. The interface is very modal in the sense that the user is constantly navigating between different parts of the app, and user actions are often linked to the part of the app that's active.
The desktop, on the other hand, has plenty of screen space and allows multiple windows. Desktop apps should be modeless -- a user doesn't navigate through the app, but sees the whole thing laid out before him or her. As much as possible, the user should be able to perform any action at any time.
For these reasons, there is no navigation controller in Cocoa similar to Cocoa Touch's UINavigationController. If you can tell us more about the tasks that your two view controllers manage, perhaps someone here will help you think of ways to translate that better to the expected desktop experience.
Here apple discusses the migrating iOS to OS X strategies. Your scenario is also discussed here:
For example, AppKit uses the NSBrowser class to manage the display of
hierarchical information; in contrast, an iOS app would use navigation
controllers.
And NSBrowser can be seen in use here with the output as shown in the attached image.
Since several days I am trying to resolve the folowing issue, reading all I found around the web about npapi on mac.
The goal is to have a npapi plugin which works for safari and firefox(mac).
My software (that I can not rewrite specialy for this purpose hase about 45000 lines of C code) is based on a NSView attached to a NSDocument....
I have a webkit version based plugin that I must trash (thanks to Apple!) based to the same NSView.
I have a npapi version plugin which works fine on firefox. In this npapi plugin, I take the carbon window ref, I make a NSWindow based on that:
NSWindow *browserWindow = [[[NSWindow alloc] initWithWindowRef:wind]autorelease];
and I put my NSView on this window and that works.
Now the pb is that I can not do the same thing on safari.
Look at attached picture, the window is not in the safari's window!
I tryed several ways... it dose not work.
Can a cocoa's gourou says where I am making something wrong? or is this a known issue?
NPError NPP_SetWindow(NPP instance, NPWindow* window){
NP_CGContext *ctx = window->window;
void *wind = ctx->window;
...
in the NSView init function:
NSWindow *browserWindow = [[NSWindow alloc] initWithWindowRef:wind];
self = [super initWithFrame:frame];
if( self )
{
[browserWindow makeFirstResponder: self];
[self setNextResponder: nil];
[browserWindow setContentView:self];
[self webPlugInInitialize];// my own initializing
}
return self;
In Safari 5.1, the web rendering is not done by Safari itself, but on a different process to enhance security. Open up the Activity Monitor, and you see that background process called "Safari Web Process" or something like that.
So, you can't and shouldn't create NSWindow based on the Carbon window ref which can be obtained within NPAPI plugin.
Read Apple's own documentation on this point. You should request the core graphics drawing method, and then the WindowRef field of NP_CGContext should have a NSWindow*, not the Carbon window ref.
If it works on Firefox, that's totally shocking and completely unsupported. Does it work in Firefox 4 and later?
If you absolutely have to use an NSView, the only way that I know to do it in a plugin is to render the NSView into your CGContext. Keep in mind that in newer NPAPI browsers with the Cocoa event system you get the CGContextRef as part of the draw event; to request a draw event you can call NPN_InvalidateWindow.
FireBreath has a completely experimental and not-fully-functional example of rendering an NSView (ans specifically a WebView) into a CGContextRef that you could look at as an example.
Other than using a CGContextRef your only other choice is to use a CALayer; if you can find a way to make a NSWindow or NSView in that you could be okay, but I don't know if there is one. Someone suggested that setting the CALayer as the rendering layer for the NSView might work. Either way you'll most likely have to forward all the events since you are basically hosting the NSView in an offscreen view.
Make no mistake; there is no supported way to get an NSView in the browser. There never has been -- methods that people have used were unsupported and depended on browser-specific implementations of the API. When you use things like that, you can reliably expect them to eventually break, such as in this case. For more information on the drawing models, you could read Stuart Morgan's blog post on the subject, check out the FireBreath mac drawing model docs, or read the Cocoa event model spec.
Given that you start with "take the carbon window ref", your approach is doomed, because it is based on the Carbon event model (and not just that, but assumptions about its internal implementation details). Anyone running Firefox on a 64-bit system will have to manually restart Firefox in 32-bit mode for your hack to work, and even then it will only work until Firefox completely removes Carbon support (which is planned for the foreseeable future).
As the other answers said, where you are going wrong is that your whole approach is completely unsupported, and the fact that it ever worked at all as an NPAPI plugin was luck. You simply cannot use an NSView directly in an NPAPI plugin.
I want to develop a plugin with Safari. Now I wan to make a demo for add a button into it's MainWindow or menu into it's MenuBar. I have seen to Document WebKitPluginProgTopic and the sample:/Developer/Examples/Webkit/WebKitMoviePlugIn . But they didn't tell the full process of make a plugin with safari and how to add some menu or button in the safari window . Someone can give me some advice or simple code to resolve this problem, Thank you very much!
The plug-in architecture isn't thought for enhancing the browser but to support special media formats like flash or quicktime. The problem is that the plugin is only loaded when the corresponding media type is found.
Agile Web Solutions have found a way to load the plug-in all sites in 1Password and insert code into Safari. They've documented it in their blog. For other means of injecting code have a look at this question: InputManager plug-ins in Snow Leopard.
I haven't got any experience in building menus programmatically, but it should work like this:
NSMenu *newMenu = [[[NSMenu alloc] initWithTitle:#"MyMenu"] autorelease];
NSMenu *mainMenu = [NSApp mainMenu];
[mainMenu addItem:newMenu];
Changing the windows isn't that easy. Your best guess is probably [NSApp orderedWindows], which exists only for scripting purposes, but should be usefull to your task.