12

I have an app with a popover that appears on a status bar item. The thing is, when you click on the icon while you're in a full screen app, then move the mouse away from the menu bar to click on something in the popup, the menu bar moves up, and so does the popup. It's annoying.

Anyone know of any way to solve this? I've tried attaching an invisible menu to the popup, but I can't get the menu to be invisible.

Screenshot for clarity, the annoying part is where I wave my mouse around:

enter image description here

tbodt
  • 16,609
  • 6
  • 58
  • 83
  • 1
    BTW - you'll not only have this issue when going full screen. On 10.11 it's possible to always automatically hide the menu bar: http://www.tekrevue.com/tip/hide-menu-bar-os-x-el-capitan/ – cacau Jan 26 '16 at 07:18
  • You might want to check out this topic, sounds like a clean solution to your problem: http://stackoverflow.com/questions/35008501/detect-if-menu-bar-is-hidden-or-visible – Jay Jan 28 '16 at 16:13
  • Unfortunately none of the answers in that question helped much in my case. The best I managed to get was detecting when the menubar becomes hidden or visible again. – Josh Jan 25 '19 at 00:45

4 Answers4

5

The popover window is moving because its parent window is the status item window, and when the parent window moves, the child moves with it. (Before I investigated this, I didn't even know Cocoa had parent and child windows.) I solved the problem with this code immediately after showing the popover:

NSWindow *popoverWindow = self.popup.contentViewController.view.window;
[popoverWindow.parentWindow removeChildWindow:popoverWindow];

Now, the menu bar still moves up, but at least the popup stays in the same place.

tbodt
  • 16,609
  • 6
  • 58
  • 83
  • 1
    Messing with windows you don't own.. wouldn't go down that route if I were you. From experience that's asking for trouble and prone to break with upcoming OS releases (or even older versions than the OS you've tested it on) – cacau Jan 28 '16 at 07:43
  • @cacau Any better ideas? – tbodt Jan 28 '16 at 17:23
  • The only other solution I found was to detach the popover when the menu-bar hides (See https://github.com/lukaskubanek/DetachablePopoverExample for detaching a popover) – Josh Jul 14 '19 at 23:48
1

Either use Carbon events or watch for things happening to the menu bar (window of type NSStatusBarWindow):

Notifications of type

  • NSWindowDidChangeOcclusionStateNotification
  • NSWindowDidMoveNotification
  • NSWindowWillCloseNotification
  • NSWindowDidCloseNotification

with an object of class NSStatusBarWindow should give you enough information about the menu bar showing or hiding to add proper handling.

Community
  • 1
  • 1
Jay
  • 6,572
  • 3
  • 37
  • 65
  • 2
    And what is the proper handling? The hard part is not finding out when the status item moves, it's preventing the popup from moving. – tbodt Jan 28 '16 at 17:24
0

Super-hacky approach:

Custom window with some super-high window level to make it appear over the menu bar, then add a transparent custom view to the new window that catches and handles/blocks mouse clicks according to your needs.

Or:

Get the window instance the popover is using to display and track/handle NSWindowWillMoveNotification / NSWindowDidMoveNotification.

cacau
  • 3,606
  • 3
  • 21
  • 42
  • Not quite what my problem is, added a screenshot to clarify. – tbodt Jan 22 '16 at 19:21
  • Ah, right! Any notifications that are sent when the menu bar hides? Just try listen to anything and watch out in particular for the ones mentioned in https://developer.apple.com/library/mac/documentation/General/Conceptual/MOSXAppProgrammingGuide/FullScreenApp/FullScreenApp.html – cacau Jan 25 '16 at 06:48
  • If there's any local notifications sent, they would be to the program that is in full screen. There might be a distributed notification, but what could I do about it? Hide the popup? That would make it impossible to use the popup in full screen mode. – tbodt Jan 25 '16 at 20:06
  • ..AppKit sends heaps of notifications all the time, worth checking. No delegate method being called for your window? For the app's menu bar? – cacau Jan 26 '16 at 07:16
  • @tbodt Or just watch out for the popover's window moving (see altered answer above) – cacau Jan 26 '16 at 07:21
  • I figured it out myself. Check my answer if you want to see how. – tbodt Jan 27 '16 at 20:46
0

I converted @tbodt's answer to Swift 4 and confirmed that is resolves this issue:

let popoverWindow = popup.contentViewController.view.window as? NSWindow
popoverWindow?.parent?.removeChildWindow(popoverWindow!)
  • As cacau has mentioned its not a good idea to mess around with internal windows. Why not to place a small hidden window near the status bar item when the popover should be presented and to relate it to a view in the hidden window. I used this technique years ago to prevent flickering during open animation. There are different popover behaviour you can use and for me, to remove it from the parent window could have an side effect. – Marc T. May 27 '18 at 05:20
  • @MarcT. Would you be so kind and provide a code snippet? I'm dealing with a similar problem, and didn't quite catch what you mean. – Pavel Lobodinský Aug 27 '18 at 07:39
  • I'd be very interested in seeing an example of this as well. I would like the popover to follow the menubar upwards, but stop when it reaches the top of the screen, so that none of the popover is cut off. – Josh Jan 25 '19 at 00:46