Using MAAttachedWindow with an NSStatusItem

I get asked how to do this disproportionately often, so I put together a sample project showing how you can have an NSStatusItem in the menubar which spawns an MAAttachedWindow instead of a menu (really, it’s ridiculously simple – no tricks involved). It looks like this:

screenshot

Could be cool for status displays, alerts, or just having a pic of your significant other floating around on your screen, and it should work on Leopard, Tiger, and very likely Panther too. You can grab the source here.

17 comments

  1. Might be a nice clean way to show Twitter updates.

  2. The code is nice and clean but one thing I was wondering about is the ability to command click and move the status item along the menubar. To be able to insert it into a different location. Is this easily added?

  3. that looks familiar

    great post matt, im glad you helped me with this, I really appreciated it!

  4. Hey, Matt…a question about this spread to the CocoaDev forums and I’d like to point out that you don’t have to put in a custom view. NSStatusItem supports target/action messages that fire when you click on the status item view. You would have to move the center-finding code around but it would eliminate the pretty-much-pointless custom view.

    Of course, if the project already uses a custom view then this is no worse.

  5. Jordy/Jediknil: I’ve been working on a project using this custom window of Matts and I don’t think you can ditch the custom view. I can’t see another way to find the position of the NSStatusItem to be able to place the MAAttachedWindow properly.

    Am I missing something?

  6. Sorry I should have mentioned that I’m trying to make the MAAttachedWindow appear periodically – not on a mouse event – kinda like growl i guess, but the arrow needs to be pointing at my NSStatusItem. Still possibly without the custom view??

  7. I’ve been playing around with the NSStatusItem and developed a hack for accessing the StatusItem location.

    @interface NSStatusItem (hack)
    - (NSRect)hackFrame;
    @end

    @implementation NSStatusItem (hack)
    - (NSRect)hackFrame
    {
    return [_fWindow frame];
    }
    @end

    This simply sub classes the NSStatusItem and add a new method “hackFrame”. Then in your code you simple call:

    NSRect itemRect = [statusItem hackFrame];

    statusItem being your object class name. The position of your NSStatusItem is returned in the NSRect.

    I’ve been using this to use the genie effect and make my views warp in and out of the status item.

    • Does not work anymore. Private instance variable are no exported anymore. So this hack, however useful it was … well was a hack that worked but no more :)

  8. Philip, you have not sub classed NSStatusItem, you’ve added an extension to the already defined class.

    With some slight modifications to MAAttachedWindow, by making the following methods public.
    - (void)_updateGeometry;
    - (MAWindowPosition)_bestSideForAutomaticPosition;
    and making the following variables protected
    @protected
    NSPoint _point;
    MAWindowPosition _side;

    I extended MAAttached window and am passing it a point when the user clicks on the menuItem.

    @implementation PPAttachedWindow

    -(void)resetClickPoint:(NSPoint)latestPoint {
    _point = latestPoint;

    //Get the screen with the menubar
    NSScreen* menuBarScreen = [[NSScreen screens] objectAtIndex:0];
    _point.y = [menuBarScreen frame].size.height + [menuBarScreen frame].origin.y – 20;

    if (_side == MAPositionAutomatic) {
    _side = [super _bestSideForAutomaticPosition];
    }

    [super _updateGeometry];
    }

    The source kode will be available when I release the next version of ogsPing.

    M@

  9. Sorry to raise this from the dead, so to speak, but I just wanted to mention that Philip’s solution works really well, and coupled with window fading, it makes for one heck of a menu… :)

    • Does not work for me anymore. I get

      Undefined symbols:
      “_OBJC_IVAR_$_NSStatusItem._fWindow”, referenced from:
      -[NSStatusItem(hack) hackFrame] in ccGpP6n1.o
      ld: symbol(s) not found

  10. Does anyone know if I could reference objects via Applescript with this? I tried

    set contents of text field “textField” of view “maView” to “foo”

    but it didn’t work. I’d like to use this in my Applescript Studio application

  11. Any idea on how to make the window float over the currently running app?

    I tried using [NSApp activateIgnoringOtherApps:YES];

    While this works, it puts the current app’s window out of focus and when you exit your own window, the focus won’t go back to the other app.

    I would like to achieve something like Spotlight or CoverSutra.

    Should I use a NSPanel instead of a NSWindow or have a whole different approach?

  12. @Luc
    [window setLevel:NSMainMenuWindowLevel];

  13. Thanks Matt! This is exactly what I was looking for.

    Only problem is when the app is backgrounded and I put a textField into the view I can’t type into it.

    Anyone know a way to make the attachedWindow the keyWindow or make text inputs available?

  14. Use [self valueForKey:@"_fWindow"] instead of directly calling the variable by its name. It works in Snow Leopard when Active Architecture set to x86_64

  15. Thanks for this class and this example. I am trying to do the same but instead of attaching it to the statusItem, I want to attach it to the app icon in the dock. Any pointer for achieving this?

    Thanks :)

Leave a comment