Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 418245

Summary: [SWT_AWT] Embedded SWT in AWT broken on Mac with Java 7
Product: [Eclipse Project] Platform Reporter: Christopher Deckers <chrriis>
Component: SWTAssignee: Platform-SWT-Inbox <platform-swt-inbox>
Status: CLOSED WONTFIX QA Contact: Lakshmi P Shanmugam <lshanmug>
Severity: blocker    
Priority: P3 CC: ahmadswaid, arunkumar.thondapu, christophe.cornu+eclipse, ciuste, dan.sonnemann, daniel_megert, djakone, egalvez, hcmc-up, joel.drigo, lethanhhoang705, lshanmug, mdaenzer, nikita, nvkaymanov, sandipsahoo789, Silenio_Quarti, snorthov, support, zandersmith
Version: 4.4Keywords: helpwanted, triaged
Target Milestone: ---   
Hardware: Macintosh   
OS: Mac OS X   
See Also: https://git.eclipse.org/r/155620
https://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=30ad38d69b91bac02f587cec89b564c73a903bdb
Whiteboard:
Attachments:
Description Flags
Simple example showing the issue. none

Description Christopher Deckers CLA 2013-09-28 06:32:19 EDT
Created attachment 235920 [details]
Simple example showing the issue.

With Java 7, embedding an SWT component in AWT/Swing (e.g.: the Browser) on Mac OS X does not work.

I was hopeful that having the fix for bug 374199 would solve it, and I have since waited for official builds. I just tried with Java 7u40 (x64) and SWT 4.4M2 (cocoa x86_64) and it is still not working.

All we get is a warning:
JAWT_GetAWT must be called after loading a JVM
... followed by an exception when creating the Browser:
java.lang.IllegalArgumentException: Argument not valid [peer not created]

I just realized that bug 374199 was the opposite issue: embedding AWT in SWT (I overlooked a particular comment in that bug... 374199#c29).
Is there something wrong in the way we integrate SWT or is it indeed broken? Any hopes of a fix in that case?

This issue is critical for all users of my library (DJ Native Swing) who had working applications that do not work anymore. Staying forever on Java 6 is less and less an option.
Comment 1 Christophe Cornu CLA 2013-12-20 09:16:15 EST
> final Shell shell = SWT_AWT.new_Shell(display, canvas_);
My understanding is that this line no longer works starting with JDK1.7. AWT Team has apparently rewritten AWT on the Mac to use CALayer's and no more NSView's. As a result, Snippet337 fails with this stack trace on latest JDK1.8EA (click on AWT Button in snippet):

JavaVM WARNING: JAWT_GetAWT must be called after loading a JVM
Exception in thread "AppKit Thread" org.eclipse.swt.SWTException: Failed to execute runnable (java.lang.IllegalArgumentException: Argument not valid [peer not created])
	at org.eclipse.swt.SWT.error(Unknown Source)
	at org.eclipse.swt.SWT.error(Unknown Source)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Unknown Source)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Unknown Source)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source)
	at Snippet337.main(Snippet337.java:77)
Caused by: java.lang.IllegalArgumentException: Argument not valid [peer not created]
	at org.eclipse.swt.SWT.error(Unknown Source)
	at org.eclipse.swt.awt.SWT_AWT.new_Shell(Unknown Source)
	at Snippet337$1$1$1.run(Snippet337.java:43)
	at org.eclipse.swt.widgets.RunnableLock.run(Unknown Source)
	... 4 more
http://git.eclipse.org/c/platform/eclipse.platform.swt.git/tree/examples/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet337.java


As you said, fix for bug 374199 is for a different scenario which was also broken by JDK1.7 on Mac. The patch allows us to run Snippet154 with JDK1.8EA. But AWT team reintroduced the functionality of CViewEmbeddedFrame backed by an NSView, but this doesn't address the issue of Canvas being now CALayer based.

The rewrite of AWT on Mac has caused issues for other projects as well, and was discussed in a few places e.g.
https://github.com/caprica/vlcj/issues/205
http://stackoverflow.com/questions/10584204/swt-browser-swing-integration-mac-jdk-1-7
Comment 2 Michael Dänzer CLA 2014-02-05 10:23:25 EST
A customer of ours needs a working browser in a swing component on macos with JRE 7 until end of june 2014. If we do not have a solution until june then we will need to use another solution omitting swt. In this issue I do not see a target milestone, so my question is obvious: Are there any plans how and when to proceed?
Comment 3 Joël DRIGO CLA 2014-03-03 08:51:42 EST
Hi Mickael Danzer,

I think you need to put SWT Browser component into SWING Component (as DJNative does) : this is the opposite of this problem, and fixed according to https://bugs.eclipse.org/bugs/show_bug.cgi?id=374199 (ie SWT R-4.3-201306052000)

Like you, I couldn't wait the release of Eclipse RCP with this fixed SWT component, so I patched it in 3.8.2 myself. I started with the code on http://www.eclipse.org/articles/article.php?file=Article-Swing-SWT-Integration/index.html, then I patched the code according to https://bugs.eclipse.org/bugs/show_bug.cgi?id=374199.

I added, in EmbeddedSwingComposite, a boolean constant, called MAC_PATCH (true means os.name is Mac OS X, and java.version starts with 1.7, or any other way to set the environment is OSX and Java7). 

I add this static block:
private final static MAC_PATCH = System.getProperty("os.name").startsWith("Mac
static {    if ( MAC_PATCH ) {
        LOG.info("SWT_AWT Bridge: patching for Apple/Oracle MacOsX/JAVA7 bugs workaround" );
    SWT_AWT.embeddedFrameClass="sun.lwawt.macosx.CViewEmbeddedFrame";        
    }
}

Then, I add the following code, after the frame creation:

 
 
...
 
final Frame frame = SWT_AWT.new_Frame(this); // j'ai juste ajouté final à la ligne d'origine de createFrame
 
if (MAC_PATCH) {
 
 
    // patch du bug tracker Eclipse 4.3.2 (<a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=374199" target="_blank">https://bugs.eclipse.org/bugs/show_bug.cgi?id=374199</a>)
 
    final Composite parent = AbstractSWTSwingNGComposite.this;
 
    // When display is disposed the frame is disposed in AWT EventQueue.
    // Force main event loop to run to let the frame finish dispose.
    final Display display = parent.getDisplay();
    display.addListener(SWT.Dispose, new Listener() {
        public void handleEvent(Event event) {
            while (frame.isDisplayable() && !display.isDisposed()) {
                if (!display.readAndDispatch()) {
                    display.sleep();
                }
            }
            //Frame finished dispose, the listener can be removed
            if (!display.isDisposed()) {
              display.removeListener(SWT.Dispose, this);
            }
        }
    });
 
    Listener listener = new Listener () {
        public void handleEvent (Event e) {
            switch (e.type) {
                      case SWT.Dispose:
                         getShell().removeListener (SWT.Activate, this);
                         getShell().removeListener (SWT.FocusOut, this);
                           break;
              case SWT.Activate:
                  if (!parent.isFocusControl()) return;
              // case géré par l'implémentation de la classe parente : case SWT.FocusIn:
                  EventQueue.invokeLater(new Runnable () {
                      public void run () {
                        if (frame.isActive()) return;
                        try {
                            Class clazz = frame.getClass();
                            Method method = clazz.getMethod("synthesizeWindowActivation", new Class[]{boolean.class});
                            if (method != null) method.invoke(frame, new Object[]{new Boolean(true)});
                            } catch (Throwable e) {
                                LOG.error("SWT_AWT ERROR",e);}
                            }
                      }
                  );
                  break;
              // case gérée par l'implémentation de la classe parente : case SWT.Deactivate:
              case SWT.FocusOut:
                  EventQueue.invokeLater(new Runnable () {
                      public void run () {
                          if (!frame.isActive()) return;
                          try {
                              Class clazz = frame.getClass();
                              Method method = clazz.getMethod("synthesizeWindowActivation", new Class[]{boolean.class});
                              if (method != null) method.invoke(frame, new Object[]{new Boolean(false)});
                          } catch (Throwable e) {
                              LOG.error("SWT_AWT ERROR",e);
                          }
                      }
                  });
                  break;
            }
        }
    };
 
 
    parent.addListener (SWT.Dispose, listener);
    parent.addListener (SWT.Activate, listener);
    parent.addListener (SWT.FocusOut, listener);
 
 
    // fin du patch du bug tracker Eclipse 4.3.2
 
 
    // les lignes suivantes sont nécessaires pour que la gestion du focus fonctionne correctement !!!
    frame.setVisible(false);
    frame.setVisible(true);    
 
 
    // autre partie reprise en partie du patch
    display.asyncExec(new Runnable() {
 
 
        @Override
        public void run() {
 
 
            if (parent.isDisposed()) return;
 
 
            final Rectangle clientArea = parent.getClientArea(); 
 
 
            try {
                Method method = frame.getClass().getMethod("validateWithBounds", new Class[] {int.class, int.class, int.class, int.class});
                if (method != null) method.invoke(frame, new Object[]{new Integer(clientArea.x), new Integer(clientArea.y), new Integer(clientArea.width), new Integer(clientArea.height)});
                parent.setFocus();
                if ( parent.isFocusControl() ) {
                    // le validateWithBounds fait perdre le focus au composant SWT, ce qui fait perdre le focus au composant AWT
                    // le fait de redonner le focus au compsant SWT ne redonne pas bizarrement le focus au composant AWT
                    EventQueue.invokeLater(new Runnable () {
                        public void run () {
                            if (!frame.isActive()) return;
                            // ce code redonne le focus à la frame AWT (un requestFocusInWindows est insuffisant, bizarrement    
                            try {
                                Class clazz = frame.getClass();
                                Method method = clazz.getMethod("synthesizeWindowActivation", new Class[]{boolean.class});
                                if (method != null) method.invoke(frame, new Object[]{new Boolean(true)});
                            } catch (Throwable e) {LOG.error("SWT_AWT ERROR",e);}
 
 
                            if ( awtContext.getSwingComponent()!=null ) {
                                awtContext.getSwingComponent().requestFocusInWindow();
                            }
                        }
                    });
                }
 
 
            } catch (Throwable e) {
                LOG.error("SWT_AWT ERROR",e);
            }
 
 
        }
    });
 
 
}
 
awtContext = new AwtContext(frame); // ligne dans le code d'origine de createFrame 
 
...

This works fine on MacOSX Java 1.7 u51, except for the DND between AWT and SWT (see my bugtracker: https://bugs.eclipse.org/bugs/show_bug.cgi?id=428634).
Comment 4 Joël DRIGO CLA 2014-03-10 06:35:11 EDT
(In reply to Joël DRIGO from comment #3)
Sorry, I made a mistake: my patch is for embedding AWT in SWT, not SWT in AWT.
Comment 5 Dani Megert CLA 2014-06-30 07:48:50 EDT
Please investigate for 4.4.1.
Comment 6 Lakshmi P Shanmugam CLA 2014-09-03 09:17:56 EDT
I've investigated the issue. The problem happens with Oracle Java as it seems that AWT Canvas is no longer backed by a NSView. We should investigate further and see if we can find a way of embedding the shell NSView on a CALayer or something.

We'll defer this for now and address it in 4.5.
Comment 7 Steve Northover CLA 2014-10-15 10:25:16 EDT
Between JDK6 and JDK7, the AWT implementation was changed to be lightweight and to use CALayers instead of NSViews as the underlying widget handle for AWT widgets.  This meant that any native code that used NSViews and expected AWT to use NSViews was broken.

There is no way to fix this easily.  AWT would need to go back to NSViews (but it won't because the browser won't work) or SWT will need to go to CALayers (but it won't because native cocoa controls are all NSViews).

It may be possible to fake up something by either toolkit creating an NSView to give to SWT but the results might not be pretty.
Comment 8 Dani Megert CLA 2014-10-15 11:50:13 EDT
(In reply to Steve Northover from comment #7)
> Between JDK6 and JDK7, the AWT implementation was changed to be lightweight
> and to use CALayers instead of NSViews as the underlying widget handle for
> AWT widgets.  This meant that any native code that used NSViews and expected
> AWT to use NSViews was broken.
> 
> There is no way to fix this easily.  AWT would need to go back to NSViews
> (but it won't because the browser won't work) or SWT will need to go to
> CALayers (but it won't because native cocoa controls are all NSViews).
> 
> It may be possible to fake up something by either toolkit creating an NSView
> to give to SWT but the results might not be pretty.

This is outside the capacity of the SWT team. Unless someone from the community steps up, we have to drop the support for that feature.
Comment 9 Steve Northover CLA 2014-10-27 15:28:46 EDT
Agree.  It has been broken since JDK7 which is quite a long time.  That's not a excuse, but it indicates that people have been able to function without this feature for a while.
Comment 10 Christopher Deckers CLA 2014-10-27 16:08:15 EDT
> it indicates that people have been able to function
> without this feature for a while.

I regularily have users of my library (which uses SWT to integrate native components in Swing) asking about the Mac integration, and I redirect them to this bug.
I also regularily have users who ask me if the issue improved.
And last but not least, I know some users who are still using Java 6 and really complain that it is not an option anymore; they don't know how to solve their problem.

I also acknowledge that it is not a trivial problem to solve...
Comment 11 Support RouteConverter CLA 2014-10-28 05:41:37 EDT
@Steve People are not able to function without this feature, they're leaving. I'm planning to migrate away from Eclipse SWT since on Mac OS X I'm effectively stuck at Java 6 and when Apple drops it, I need an alternative.
Comment 12 Eddie Galvez CLA 2014-11-13 11:48:39 EST
We have a product that has been using the SWT/AWT bridge, and at the moment I can verify that running under Java 6, on OS X, I have no problems.

As soon as I run under Java 7, I get an issue whereby a java.awt.Frame does not layout properly;  the Frame does not fill the composite it got created from! Are there any workarounds that are available?
Comment 13 Lakshmi P Shanmugam CLA 2015-04-14 09:13:22 EDT
We will not be able to fix this in Eclipse 4.5. Resetting the target.
Comment 14 Djak CLA 2015-04-28 08:32:56 EDT
Hi,
I have exactly the same problem as Eddie #12 (by embedding an AWT Frame in a SWT Composite, using JDK > 6, the AWT Frame is not displayed or, after resizing the Editor, the AWT Frame is glitched, got wrong dimensions and the AWT events are also not detected.
I'm really sorry, I don't really understand the original issue and if the behavior can be linked to it. Do you think it can ? or maybe someone could help me to find the right issue/bug ?
Also maybe anyone have found a temporary workaround for this bug ?
Thank you very much in advance for your help and please forgive me if I'm not really at the right location.
Comment 15 Lakshmi P Shanmugam CLA 2015-06-11 05:26:20 EDT
(In reply to Djak Mising name from comment #14)
> Hi,
> I have exactly the same problem as Eddie #12 (by embedding an AWT Frame in a
> SWT Composite, using JDK > 6, the AWT Frame is not displayed or, after
> resizing the Editor, the AWT Frame is glitched, got wrong dimensions and the
> AWT events are also not detected.
> I'm really sorry, I don't really understand the original issue and if the
> behavior can be linked to it. Do you think it can ? or maybe someone could
> help me to find the right issue/bug ?
> Also maybe anyone have found a temporary workaround for this bug ?
> Thank you very much in advance for your help and please forgive me if I'm
> not really at the right location.

This bug tracks the problem with embedding SWT in AWT. But, you are embedding AWT in SWT which should work fine. Please open a separate bug for this issue. Also, you need to use Java 7 update 40 or later (due to Bug 374199). Please find some example snippets on how to use the SWT_AWT bridge here -- https://www.eclipse.org/swt/snippets/ under bullet Swing/AWT.
Comment 16 Djak CLA 2015-06-18 08:24:56 EDT
Hi,
thank you for your answer. After further investigation, I add this last comment to clarify my issue (comment #14) that is finally not linked to this one (and also doesn't seem to be linked to SWT).
The problem is on some OS X configurations, Java 1.7/1.8 can not enable hardware acceleration, leading to a CPU usage reaching sometimes 80% when the layout resizing is done even when using only AWT code (no SWT code at all). The message in RCP console is "WARNING: GL pipe is running in software mode". The behavior is a few different when embedding AWT in SWT in an RCP application, it simply creates glitched components or does not create them at all and freezes the app.
(I didn't found any solution at this moment for this, except stay in Java 1.6)
Comment 17 Lakshmi P Shanmugam CLA 2017-07-03 01:03:56 EDT
Bug triaged, visit https://wiki.eclipse.org/SWT/Devel/Triage for more information
Comment 18 Nikita Kaymanov CLA 2017-08-14 11:09:04 EDT
Have the same problem. Voted.
When will be solved this bug?
Comment 19 ahmad swaid CLA 2018-02-22 06:01:00 EST
I have the same problem described here.
Any update how to solve it.
Comment 20 Eclipse Genie CLA 2020-01-10 12:06:51 EST
New Gerrit change created: https://git.eclipse.org/r/155620
Comment 22 Nikita Nemkin CLA 2020-01-25 09:34:13 EST
Unfortunately, this can't be fixed. AWT internals have changed in Java 7 and the necessary API isn't available anymore.