Tk Source Code

View Ticket
Login
Ticket UUID: 07cfc9f03ef7840036f9f79933f23e7154d1308
Title: Aqua: Non-menubar menu invisible if toplevel is on another display
Type: Bug Version: 8.6.9
Submitter: chrstphrchvz Created on: 2019-02-28 05:41:26
Subsystem: 11. Aqua Menus Assigned To: nobody
Priority: 5 Medium Severity: Minor
Status: Closed Last Modified: 2025-08-14 21:01:57
Resolution: Fixed Closed By: chrstphrchvz
    Closed on: 2025-08-14 21:01:57
Description:

If multiple displays are used, and a toplevel with a menu is located on a different display than the root window, then posting the menu will not cause the menu to visibly appear. The menu is posted, though: it can be interacted with programmatically and with the mouse or keyboard.

Note that I observe this using essentially two graphics cards (one is connected via built-in DisplayPort, the other is connected to a DisplayLink USB adapter), so I don't know this is the case for multiple displays connected to the same graphics card.

User Comments: chrstphrchvz added on 2025-08-14 21:01:57:

Revised fix is now applied to core-8-6-branch.


marc_culler (claiming to be Marc Culler) added on 2025-08-14 20:15:11:
Yes, please do.

chrstphrchvz added on 2025-08-14 19:26:26:

Thanks, Marc. Would it be okay then to apply it to 8.6 as well?


marc_culler (claiming to be Marc Culler) added on 2025-08-10 16:20:21:
I am OK with it.

PS Thanks for the other recent patches.  I will get to them before too long.

chrstphrchvz added on 2025-08-09 18:50:40:

I now notice that Tk 9 contains the approach from ca2ebe1fca-fix.diff (i.e. use the undocumented appearance: argument). It was included in the initial changes for CGImage drawing ([a7e2553a07]), and so was likely accepted unintentionally. Are the Tk Aqua maintainers okay with keeping this approach?


chrstphrchvz added on 2022-09-05 00:25:51:

I notice that this issue only seems to be present when the System Preferences setting “Displays have separate spaces” is enabled. (Reasons for having this enabled is that it allows using multiple displays when an app is fullscreen; the only reason I’m aware of to have it disabled is that it does not allow a single non-fullscreen window to span multiple displays—I wonder if this is the underlying cause, which could indicate an bug in AppKit menu APIs.)

The behavior is different when this setting is disabled, but I’m not sure I can accurately and exhaustively describe how. With the existing approach in core-8-6-branch, menus can be posted programmatically on a different display than the toplevel, but for some reason posting a menu in response to a mousebutton click seems to always post the menu to the same display as the toplevel even when the coordinates are hardcoded.

Whether multiple graphics cards are used may not matter because of this setting.


chrstphrchvz added on 2022-08-06 05:02:27:

Please see attached patched ca2ebe1fca-fix.diff


chrstphrchvz added on 2022-08-06 01:40:56:

I misunderstood jal_frezie’s comment. That issue is apparently due to a limitation when using popUpMenuPositioningItem:atLocation:inView: with a specific NSView. The approach suggested in my comment dated 2019-08-10 02:52:55 does not have this limitation. I would like to see if Tk Aqua developers are okay with using the undocumented appearance: argument so as to avoid a regression where menus have light/dark appearance based on what is set in System Preferences rather than what may be set for a specific toplevel. I will see if I can come up with a patch for testing…


chrstphrchvz added on 2022-08-04 22:37:09:

That sounds like a regression. I will check if I can reproduce the issue.


jal_frezie added on 2022-08-04 11:23:47:
Note that a menu will still not visibly appear (as of version 8.6.12) if posted on a different display than its own toplevel window.

kevin_walzer added on 2019-09-02 01:55:59:
This patch does address the problem, and appears to have no side effects. Thanks for the patch; committing to trunk and core-8-6-branch.

chrstphrchvz added on 2019-08-31 22:17:09:

I have attached a new patch 07cfc9f0-fix.patch which I believe fixes the problem. There might be better choices for some of the variable names I used.

The approach used in the patch looks for the parent window of the menu that is a "real" (i.e. non-menu) toplevel with an associated NSView; this NSView is then what is used, rather than always using the one associated with the root toplevel window. This approach appears to fix both issues of menus not appearing on a different display than the root window, and menus only using the appearance of the root window even when a different appearance is set for the menu's parent real toplevel window. I am not aware of any potential regressions this approach might introduce.

The patch can be tested using the attached demo, menutest.tcl. The demo creates menus for both the root window and a child toplevel, and sets the appearance of the root window to aqua (light appearance) while setting the child toplevel's appearance to darkaqua. Clicking inside of the root window should display a menu with a light appearance; and clicking inside of child toplevel should display a menu with a dark appearance, even after dragging the root window or child toplevel to a different display than the other.


kevin_walzer added on 2019-08-11 02:20:36:
As I don't use a dual monitor setup, I am unable to test this, but the menu should continue to pick up the system display mode (dark or light) - if this patch causes the menu to always display as light, then that is a regression.

chrstphrchvz added on 2019-08-10 19:30:39:

However, I haven't figured out how to get the appearance for a menu, nor have I figured out how to get the toplevel for one, since it doesn't seem to be recorded in menuPtr->tkwin->privatePtr->toplevel

I have probably misunderstood the purpose of this toplevel field, and more importantly neglected that a menu is a toplevel window, at least on other platforms—I don't know to what extent this is still true for Aqua.

Someone more knowledgable about AppKit and the existing code might know how to get the correct view, if that's indeed the cause; I suspect this might be easy to fix for someone who already knows where to look.

If a proper solution for this issue can't be found yet, though, then I think it would be better to incorporate the workaround I found in time for 8.6.10. That way, menus for anyone working on multiple monitors are at least usable, even though they won't support dark appearance (which is new in 8.6.10, or at least unknown to anyone who hasn't tried trunk or core-8-6-branch). I am attaching a brief patch for the workaround.


chrstphrchvz added on 2019-08-10 02:52:55:

I updated the description to be more precise.

I'm inclined to think that the cause of this issue is that, in TkpPostMenu() (tkMacOSXMenu.c), the view of the root window is always used in the call to popUpMenuPositioningItem:atLocation:inView:; it should instead use the view for the toplevel containing the menu.

Some observations:

  • Menus always use the appearance of the root window rather than their toplevels. If the appearance of a toplevel is overridden with ::tk::unsupported::MacWindowStyle appearance, that toplevel's menus are unaffected; but if the root window's appearance changes, then so will that of any menus, regardless of which toplevel they belong to.
  • Replacing

        [menu popUpMenuPositioningItem:item
    			atLocation:[win tkConvertPointFromScreen:location]
    			    inView:view];
    with
        [menu popUpMenuPositioningItem:item
    			atLocation:location
    			    inView:nil];
    does allow menus of a non-root toplevel to appear on a different monitor than the root window. With this approach, menus will always use a light appearance, unless an undocumented appearance: argument is also specified. However, I haven't figured out how to get the appearance for a menu, nor have I figured out how to get the toplevel for one, since it doesn't seem to be recorded in menuPtr->tkwin->privatePtr->toplevel. Even doing
    menu .m;
    ::tk::unsupported::MacWindowStyle appearance .m
    will crash with:
    Failed to read appearance name.
    Abort trap: 6
    .


Attachments: