Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 307302 - [SWT_AWT] SWT interfers with application menu
Summary: [SWT_AWT] SWT interfers with application menu
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 3.6   Edit
Hardware: PC Mac OS X
: P3 major with 7 votes (vote)
Target Milestone: 3.7   Edit
Assignee: Scott Kovatch CLA
QA Contact: Silenio Quarti CLA
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-03-28 05:55 EDT by Christopher Deckers CLA
Modified: 2011-12-03 04:08 EST (History)
8 users (show)

See Also:


Attachments
Test case with boolean to try different scenarios. (5.19 KB, text/x-java)
2010-03-28 05:58 EDT, Christopher Deckers CLA
no flags Details
Revised test case (4.63 KB, application/octet-stream)
2010-09-27 17:25 EDT, Scott Kovatch CLA
no flags Details
Issue on Mac OS X 10.5 with Java 5 (204.07 KB, image/png)
2010-11-12 10:57 EST, Christopher Deckers CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Christopher Deckers CLA 2010-03-28 05:55:07 EDT
Build Identifier: 3.6M6

An AWT/Swing user interface may or may not decide to use the screen menu bar. The various configuration tweaks are:
1. Setting the "apple.laf.useScreenMenuBar" system property to "true".
2. Setting the "com.apple.mrj.application.apple.menu.about.name" system property to whatever name.
3. Invoking "com.apple.eawt.Application.getApplication().addApplicationListener(listener)" to hook to the various application menu items.
4. com.apple.eawt.Application.getApplication().setEnabledPreferencesMenu(true);

Adding an SWT control must not interfer with the menus that appear in that bar, which is not the case currently. This is a showstopper for some of my users.

SWT should detect that AWT is in the picture and not touch the application menu.

Reproducible: Always

Steps to Reproduce:
1. Create an AWT/Swing application.
2. Configures the application menu bar through Mac-specific system properties and APIs.
3. Embed an SWT control
=> menus are not the ones expected.
Comment 1 Christopher Deckers CLA 2010-03-28 05:58:37 EDT
Created attachment 163171 [details]
Test case with boolean to try different scenarios.

Here is an AWT/Swing test case that allows trying with and without embedding SWT, and with and without configuring the default application menu.
Note that when trying the embedded SWT mode, you need the "-XstartOnFirstThread" flag.
Comment 2 Christopher Deckers CLA 2010-03-28 06:01:12 EDT
I forgot to mention that this bug was found using 3.6M6, but we also tried the N20100326-2000 nightly with same issues.
Comment 3 Viktor Nordling CLA 2010-03-30 11:01:55 EDT
We are very keen on seeing this bug fixed.

The biggest issue is that nothing happens when you choose Quit in the menu. If that would work, I'm sure we could work the fact that we cannot add our own items to the menu.
Comment 4 Christopher Deckers CLA 2010-03-30 11:37:59 EDT
(In reply to comment #3)
> The biggest issue is that nothing happens when you choose Quit in the menu. If
> that would work, I'm sure we could work the fact that we cannot add our own
> items to the menu.

While this may suit your particular need, I think this would definitely not be enough, because:
a. System.exit() may not be what the users expect within a Swing application. They want there shutdown procedure to be called.
b. If they took the time to configure preferences and the like, they expect them to work even after adding a 3rd party lib that internally uses SWT.

I hope the fix is as simple as preventing SWT to hook to the application menu, which would obviously satisfy everyone.
Comment 5 Viktor Nordling CLA 2010-03-30 11:42:28 EDT
Good point, I'll rephrase: 

If a workaround could be found for making the application quit, I'd be happy to use that until the real bug has been fixed.
Comment 6 Scott Kovatch CLA 2010-05-27 12:22:47 EDT
Ouch. I didn't see this because it was tagged as "Mac OS X", not "Mac OS X - cocoa". May not make it for 3.6, but maybe 3.6.1.
Comment 7 Scott Kovatch CLA 2010-05-27 12:45:45 EDT
Targeting 3.6.1. We're way too late for 3.6 at this point, but this is a good candidate for 3.6.1.
Comment 8 Christopher Deckers CLA 2010-05-27 17:09:18 EDT
(In reply to comment #6)
> Ouch. I didn't see this because it was tagged as "Mac OS X", not "Mac OS X -
> cocoa". May not make it for 3.6, but maybe 3.6.1.

Ouch indeed, I get more and more people hitting this issue and asking me if a fix is coming soon. They say they cannot ship on OS X with such a messed up menu. It is a pity that this bug got trapped in a Bugzilla black hole :)
Comment 9 Scott Kovatch CLA 2010-05-28 12:57:30 EDT
I'm not convinced this is an SWT bug yet, but I think we can find a way to work around it in the SWT. The AWT normally sets up the menu bar when the it is first loaded, but because the AWT thinks the SWT is in use, it doesn't do it. If I comment out all of our menubar setup in Display.applicationWillFinishLaunching we'll get the bare-minimum application menu but not the AWT-generated menu.

I believe the AWT makes the assumption that it will not be controlling the menu bar when -XstartOnFirstThread is used to launch the VM, so it doesn't set up the EAWT listeners. We may need to find a way to force it to do so if the screen menubar property is set.
Comment 10 Mike Swingler CLA 2010-05-28 18:38:19 EDT
(In reply to comment #9)
> I'm not convinced this is an SWT bug yet, but I think we can find a way to work
> around it in the SWT. The AWT normally sets up the menu bar when the it is
> first loaded, but because the AWT thinks the SWT is in use, it doesn't do it.
> If I comment out all of our menubar setup in
> Display.applicationWillFinishLaunching we'll get the bare-minimum application
> menu but not the AWT-generated menu.
> 
> I believe the AWT makes the assumption that it will not be controlling the menu
> bar when -XstartOnFirstThread is used to launch the VM, so it doesn't set up
> the EAWT listeners. We may need to find a way to force it to do so if the
> screen menubar property is set.

The AWT won't allow the eAWT NSApplication subclass to initialize unless the class of NSApp is *exactly* NSApplication. If you install in your own NSApp, the usually means that you are completely in control of how preferences/about/quit/etc. are handled.

If the eAWT is initialized, and the NSApp is swapped out later by the SWT, the eAWT listeners won't fire, because the hooks all hang off of it's own NSApplication subclass.
Comment 11 Scott Kovatch CLA 2010-06-02 17:06:28 EDT
(In reply to comment #10)
> The AWT won't allow the eAWT NSApplication subclass to initialize unless the
> class of NSApp is *exactly* NSApplication. If you install in your own NSApp,
> the usually means that you are completely in control of how
> preferences/about/quit/etc. are handled.
> 
> If the eAWT is initialized, and the NSApp is swapped out later by the SWT, the
> eAWT listeners won't fire, because the hooks all hang off of it's own
> NSApplication subclass.

Isn't (one of) the problem the order of initialization? If the AWT is loaded first it gets to determine which NSApplication or subclass will be used. In the attached test case, the AWT is loading first because UIManager.setLookAndFeel gets called. By the time control reaches Display's construction I see we already have a sharedApplication of type NSApplication, with 'isRunning' returning true.

I think the other problem is that the AWT assumes a Carbon SWT, so it's calling NSApplicationLoad(). For 64-bit that's not a valid assumption, of course, but I'm not sure how the AWT could know a Cocoa SWT is about to launch.
Comment 12 Christopher Deckers CLA 2010-06-02 17:15:47 EDT
> Isn't (one of) the problem the order of initialization?

In AWT/SWT mixing, AWT or SWT code could be invoked first (Display could be created as first line, UIManager call, etc.). Are you saying there is some sort of auto-detection (heuristic-like) to activate certain modes?

> I think the other problem is that the AWT assumes a Carbon SWT, so it's calling
> NSApplicationLoad(). For 64-bit that's not a valid assumption, of course, but
> I'm not sure how the AWT could know a Cocoa SWT is about to launch.

We already have to specify -XstartOnFirstThread so I guess it would not be worse if we could hint certain aspects using new flags (-XloadCocoa, etc.). Would that make sense?
Comment 13 Scott Kovatch CLA 2010-06-02 18:26:19 EDT
(In reply to comment #12)
> In AWT/SWT mixing, AWT or SWT code could be invoked first (Display could be
> created as first line, UIManager call, etc.). Are you saying there is some sort
> of auto-detection (heuristic-like) to activate certain modes?

Normally, when the AWT starts up it checks to see if an NSApplication is running. If one is running it goes into 'embedded mode' for applet or embedded-frame support. If no NSApplication is running the AWT would normally create its own and start handling events. If '-XstartOnFirstThread' was specified it assumes a Carbon SWT will be starting up to pump the event loop, if it hasn't started already. Using this startup logic, the AWT behaves properly whether an SWT Display has been created or not.

This needs to be handled by some kind of special case in the AWT. An AWT Frame or signed applet with full permissions embedded in a Cocoa or Carbon application isn't able to use the eAWT either because the AWT doesn't 'own' the menu bar in that situation.

> We already have to specify -XstartOnFirstThread so I guess it would not be
> worse if we could hint certain aspects using new flags (-XloadCocoa, etc.).
> Would that make sense?

It would. I was thinking more along the lines of looking at what's in the classpath or examining the 'osgi.ws' property but that means the AWT needs knowledge of the SWT and I'd like to avoid that. I also think that a system property might be the better choice in this case, as '-X' flags are usually reserved for things that affect the Java launcher.
Comment 14 Scott Kovatch CLA 2010-06-14 17:56:48 EDT
After talking to Mike this will have to wait for 3.7 and a Java update. The eAWT needs to expose its application delegate implementation and then the SWT needs to change its delegate implementation to hand off notifications to both the SWT and AWT as needed.
Comment 15 Scott Kovatch CLA 2010-09-27 17:17:26 EDT
I plan to check in a fix for this today, but I want to add a few observations.

-- I now understand better some of the reasons why folks want to use the eAWT in an SWT application. If folks feel that they need to use the eAWT because they can't do something in the SWT, then we should try to address that. I don't want to match the eAWT's application listener interface method for method, so if there's a specific feature you want to see please file a new bug.

For example, the only way to listen to the application menu items is via the ApplicationListener interface. We plan to have an SWT equivalent in 3.7 with a new API for accessing application menu items.

To implement the equivalent of handleOpenFile, add a listener to the current Display for SWT.OpenDocument. The name of the file is in the 'text' field of the Event.

To implement the equivalent of ApplicationListener.handleQuit, add a listener to the current Display for SWT.Close. If you're not ready to close, set the doIt field of the event to false and the application won't quit. Note that due to the way the AWT is implemented something must call System.exit(); the application will not automatically exit once the last AWT window is closed.

Because of this, I recommend that you use either an eAWT handleQuit listener or listen for Display to send SWT.Close but not both.

-- I fixed Display startup so that apple.laf.useScreenMenuBar will work as long as you set it before the AWT starts up.

-- I added support for com.apple.mrj.application.apple.menu.about.name, but you should use Display.setAppName() instead. That will take precedence over the MRJ property. The precedence is:

  Whatever was set with -Xdock:name
  The string set with Display.setAppName()
  If the application is bundled, the value of CFBundleName from your info.plist
  The property value for "com.apple.mrj.application.apple.menu.about.name"
  "SWT" if nothing else was set.

Once a Display object has been created the name cannot change.

-- eAWT application handlers won't work unless the AWT starts before the SWT. This is a limitation of the AWT, because the necessary native code isn't loaded until the AWT loads, and I don't want to pull in the entire AWT on the chance that someone wants to use the eAWT. I have a request in to Apple to provide a notification that will fire when the AWT has loaded, and then I can create the AWT's application delegate that will handle the application menu items. When that request is implemented I can remove this restriction.

-- If you start the AWT first, you may not be able to receive SWT.OpenDocument events. I didn't test this, but I believe that when the AWT calls NSApplicationLoad() none of the default AppleEvent handlers are set up, so the SWT won't receive them.

I will try to expand on this in a blog post, but these are the important points.
Comment 16 Scott Kovatch CLA 2010-09-27 17:23:43 EDT
Fixed > 20100927.
Comment 17 Scott Kovatch CLA 2010-09-27 17:25:46 EDT
Created attachment 179693 [details]
Revised test case

Slightly modified test case describing some of the things in my previous message.
Comment 18 Christopher Deckers CLA 2010-11-12 10:57:44 EST
Created attachment 183006 [details]
Issue on Mac OS X 10.5 with Java 5

Scott,

I have a user who has an issue:
- They need compatibility with Mac OS X 10.5.
- They use JNI extensively, only 32bit.
- There is either Java 6 64 bit (not an option) or Java 5 for 10.5.
- Java 5 shows 2 apple menus (see screenshots) which is a showstopper for them.

I believe the fixes to support AWT configurations are in Java 6. Isn't there a (hidden?) way to prevent SWT from touching the menus at all so that AWT becomes the only source of configuration? If there is no such way, then I guess this user is stuck so suggestions are welcome.
Comment 19 Scott Kovatch CLA 2010-11-12 12:53:24 EST
(In reply to comment #18)
> I believe the fixes to support AWT configurations are in Java 6. Isn't there a
> (hidden?) way to prevent SWT from touching the menus at all so that AWT becomes
> the only source of configuration? If there is no such way, then I guess this
> user is stuck so suggestions are welcome.

I might be able to do a version check so the SWT doesn't load up the menus, but I'll have to test it out. Does that happen on all SWT_AWT apps? I.e, no special test case required?
Comment 20 Christopher Deckers CLA 2010-11-12 12:56:26 EST
(In reply to comment #19)
> Does that happen on all SWT_AWT apps? I.e, no special
> test case required?

I asked that user to run your test case on 10.5 with Java 5, the screenshot is the result of that test case. If there is anything else to test, please let us know.