codecentric / NSMenuFX

Other
128 stars 27 forks source link

child window cancel close of main window #19

Closed msarmc closed 8 years ago

msarmc commented 8 years ago

I have an application that I moved from Windows to Mac. It creates child windows from the parent window. A child window can cancel the close of the application. However, the sequence of events is causing a problem. When I execute Command Q, the main windows closes first. I can still cancel the close of the child window but the main window is gone. Is there an option that I'm missing that causes the child windows to try to close first? I've attached a modified form of StandardMacApp that shows what I want to do. Thanks. StandardMacApp.java.zip

0x4a616e commented 8 years ago

Interesting case, I never thought about that. I think it should be possible already by creating a custom quit menu item with a respecive action. However, I can see that this is going to be a bit tedious to do that manually, so I'll think about adding this to NSMenuFX. Can you maybe provide a bit more details about the default behavior on Windows? Are windows closed in any particular order? Witch one is closed last; the focused one, the primary stage, etc.?

msarmc commented 8 years ago

I have to completely control the closing of the main and child windows on Windows. When Exit is selected on the main window, the close decoration is clicked, or Exit is selected on a child window, I check all open child windows before allowing the main window to close. If any child window returns the cancel signal then I stop closing any remaining open windows including the main window. The main window is always the last one closed even if Exit was called from a child window. I have a couple of other issues as well, but I wanted to see if getting this one cleared up will solve those as well.

0x4a616e commented 8 years ago

Hmm, that sounds to me rather specific. In general, when you execute Command+Q you will not be to stop the app from exiting. I think what you need to do is to create a custom quit menu like this:

private MenuItem createQuitMenuItem(String appName, Stage primaryStage) {
    MenuItem quit = new MenuItem("Quit" + appName);
    quit.setAccelerator(new KeyCodeCombination(KeyCode.Q, KeyCombination.META_DOWN));
    quit.setOnAction((event) -> {
        StageHelper.getStages().stream().filter(stage -> stage != primaryStage).forEach(Stage::close);
        primaryStage.close();
    });
    return quit;
}

This allows you to control the order in which stages are closed and to close the main stage last. However, in your scenario i think it would be enough to just close all stages and make sure to set Platform.setImplicitExit(true);.

msarmc commented 8 years ago

I will try that but there is a twist. If I do not call setApplicationMenu I get a Java menu that has Quit com.myapp.MyApp and the menu I create with NSMenuFX that has Quit MyApp. If I execute Quit com.myapp.MyApp and cancel the close of a child window, the quit is canceled.

0x4a616e commented 8 years ago

This menu item will also have the desired title when you use your custom quit menu here https://github.com/codecentric/NSMenuFX/blob/master/src/test/java/de/codecentric/centerdevice/sample/StandardMacApp.java#L50 instead of the default one.

However, I sense that the problem you describe is somehow related to the quit action I use here https://github.com/codecentric/NSMenuFX/blob/master/src/main/java/de/codecentric/centerdevice/glass/MacApplicationAdapter.java#L42

There, Platform.exit() will be called unconditionally and will thus basically overrule everything you do by consuming the close event. I'll check how that can be changed.

msarmc commented 8 years ago

That is the same spot I traced the problem to. Thanks for looking into this. I appreciate you making this code available. It made my application conversion to Mac so much easier.

0x4a616e commented 8 years ago

I've uploaded a new version 2.1.4 where you can now do:

MenuToolkit tk = MenuToolkit.toolkit();
tk.setForceQuitOnCmdQ(false);

This brings back the default behaviour of JavaFX and will no longer call Platform.exit() after pressing Cmd-Q.

msarmc commented 8 years ago

I need to do some more testing but so far it works perfectly. Thank you so much.

msarmc commented 8 years ago

This is working great. The only issue I have is I start a sub application (separate JVM) using ProcessBuilder. The application menu is fine except the menu name is Java instead of the application name. Do you know offhand how I can fix this? I'm not looking for you to make more changes I was just hoping you might know the cause of this.

0x4a616e commented 8 years ago

Thats good to hear! Unfortunately, setting the application menu name at runtime is just not supported. So the only way to do that is by bundling the app and providing a .plist file with the respective name in the CFBundleName property.