-
Notifications
You must be signed in to change notification settings - Fork 521
8354539: [macOS] ComboBox and Spinner disable system menu bar shortcuts #1848
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
…before sending it to NSApp.mainMenu. Various bits of cleanup and correct handling of the popup redirector.
…to sysmenuinplatform
👋 Welcome back mfox! A progress list of the required criteria for merging this PR into |
❗ This change is not yet ready to be integrated. |
|
Webrevs
|
/reviewers 2 |
@kevinrushforth |
@@ -901,7 +901,6 @@ WindowEventDispatcher createInternalEventDispatcher() { | |||
return new WindowEventDispatcher(new PopupEventRedirector(this), | |||
new WindowCloseRequestHandler(this), | |||
new EventHandlerManager(this)); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should remove this unrelated change.
@@ -31,4 +31,8 @@ public interface MenuBarDelegate { | |||
// removes a submenu at {@code pos} which delegate is {@code menu} parameter | |||
public boolean remove(MenuDelegate menu, int pos); | |||
public long getNativeMenu(); | |||
// Returns true if the key event was processed | |||
default public boolean handleKeyEvent(int code, int modifiers) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be public default
or just default
as everything is always public in an interface anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Java part looks like a simple enough change. I can't comment on the native code.
if (supported == SupportedState.TRUE && event.getEventType() == KeyEvent.KEY_PRESSED && (event instanceof KeyEvent)) { | ||
Toolkit.getToolkit().getSystemMenu().handleKeyEvent((KeyEvent)event); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (supported == SupportedState.TRUE && event.getEventType() == KeyEvent.KEY_PRESSED && (event instanceof KeyEvent)) { | |
Toolkit.getToolkit().getSystemMenu().handleKeyEvent((KeyEvent)event); | |
} | |
if (supported == SupportedState.TRUE && event.getEventType() == KeyEvent.KEY_PRESSED && event instanceof KeyEvent ke) { | |
Toolkit.getToolkit().getSystemMenu().handleKeyEvent(ke); | |
} |
Or perhaps the instanceof is even superfluous, as you already verify it is a KEY_PRESSED event.
They definitely shouldn't, but I think that's how the poor man's focus/event delegation is currently implemented in these controls. |
On a surface, this looks like a rather intrusive change (I can't comment on the merits of this PR yet). Would it make sense to attempt fixing event consumption bugs in the ComboBox and Spinner first? |
When a Spinner is the focus owner it receives all KeyEvents but KeyEvents still need to be delivered to its editor. There's no good way of doing that now short of consuming the original event and firing a copy. To fix this we would have to introduce new API's (like some form of PR #1632).
Those bugs have to do with how consumption is signaled which isn't relevant. All that's relevant is that the original event is being consumed, not how we find out about it. JavaFX handles events using dispatch chains and currently the system menu doesn't participate in that machinery. This causes it to work very differently from a standard MenuBar (which places its accelerators in the Scene which is in the chain). One could argue that it's a bug that the system menu doesn't respond to KeyEvents the way a standard MenuBar would. Another way to look at it: do we want to outlaw what ComboBox and Spinner are doing? It's not illegal to create a KeyEvent and fire it at a control. It's not illegal to consume a KeyEvent that originated in Glass. Things only fail when the system menu is in effect and, again, only because it doesn't participate in dispatch. Because I agree with you, this PR is intrusive. I'm not fan and I wrote it. I think the system menu needs to participate in event dispatch and I haven't found any clean, tidy way of doing that. |
I am not a fan of #1632, I think it's an attempt to band-aid over a fundamental design issue, but this is a different topic altogether. Why would a Spinner or ComboBox consume the key events that it is not supposed to? Ok, let's assume the outer control (Spinner or ComboBox) gets the event and fires a copy to the inner control (TextField). This is perfectly legal, but now it must either consume the event if the secondary event is consumed. More importantly, it should not consume the event if the secondary event is not consumed, isn't that the issue? So it it a responsibility of the entity that creates the secondary event to either consume the original event or let it go, or am I mistaken? |
Good point, it's not and shouldn't be strictly illegal. I only commented earlier that I think they shouldn't be doing it but currently have little recourse. It should be perfectly fine to create your own KeyEvent or MouseEvent, and IMHO such events should be able to do anything that system created events can do, including firing system menus. That ship may have sailed though as I think there's already data in these events that users can't create or replicate. |
A control can't just fire an event "to the inner control" using the usual I don't know what "outlaw" means in this case. Throw an exception when user code tries to fire input events? No, probably not. But in my view we should consider it as a control bug, not as a legitimate use of the event system. |
If we decided to fix this in controls and discard this PR as unnecessary I would not shed any tears. I knew this would be clunky but felt we at least needed to get a look at a fix like this. I also wanted this in hand since the timeline for fixing this in controls is uncertain. |
This would mean two unconsumed KeyEvents would bubble all the way up to the scene. This could trigger the same MenuItem twice even though the user only pressed the accelerator once. |
The Mac platform code sends a KeyEvent into the scene graph and if the event is not consumed it gets sent on to the system menu. But ComboBox and Spinner always consume the original event and fire a copy which the system menu ignores.
In the past the platform code sent key events to the system menu even if the scene graph consumed them. This caused various bugs and was fixed in PR #1528 leading to this issue.
One could argue that a ComboBox or Spinner shouldn’t consume all key events but one could also argue that the system menu shouldn’t behave so differently from a standard MenuBar which will respond to any KeyEvent that reaches the top-level Scene no matter where it came from.
This PR installs an event dispatcher which forwards KEY_PRESSED events on to the platform so any event bubbling through the dispatch chain can trigger the system menu. The dispatcher is placed by the top-level (non-popup) Window such that it’s the last dispatcher encountered while bubbling.
In this PR once the key event reaches the GlassSystemMenu it passes the JavaFX key code and modifiers into the Mac platform code. This isn’t enough information to construct an NSEvent to pass to the main menu. Instead the code uses the code and modifiers to verify that the originating key down NSEvent (which it retained) should be sent on to NSApp.mainMenu.
(There are other ways this could work. GlassSystemMenu could take the KeyEvent and perform its own accelerator matching entirely inside Java. This would match the way the standard MenuBar finds accelerators instead of using Apple’s matching algorithm. This PR is the more conservative approach, basically just shifting the timing of system menu matching without changing how it’s done.)
Progress
Issue
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jfx.git pull/1848/head:pull/1848
$ git checkout pull/1848
Update a local copy of the PR:
$ git checkout pull/1848
$ git pull https://git.openjdk.org/jfx.git pull/1848/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 1848
View PR using the GUI difftool:
$ git pr show -t 1848
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jfx/pull/1848.diff
Using Webrev
Link to Webrev Comment