Reputation: 69
I am on a Mac ( tested it with 10.6.4, 10.7.5 & 10.8.2 ) with my desktop zoomed. When lunching my Java application that use both Swing and SWT the window is freezing right at the opening. The issue can also be reproduced with the snippet 337 provided on SWT webpage (here is a link).
package org.eclipse.swt.snippets;
/*
* SWT_AWT example snippet: launch SWT from AWT and keep both active
*
* For a list of all SWT example snippets see
* http://www.eclipse.org/swt/snippets/
*/
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.*;
public class Snippet337 {
public static void main(String args[]) {
final Display display = new Display();
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame mainFrame = new JFrame("Main Window");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new FlowLayout());
JButton launchBrowserButton = new JButton("Launch Browser");
launchBrowserButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFrame childFrame = new JFrame();
final Canvas canvas = new Canvas();
childFrame.setSize(850, 650);
childFrame.getContentPane().add(canvas);
childFrame.setVisible(true);
display.asyncExec(new Runnable() {
public void run() {
Shell shell = SWT_AWT.new_Shell(display, canvas);
shell.setSize(800, 600);
Browser browser = new Browser(shell, SWT.NONE);
browser.setLayoutData(new GridData(GridData.FILL_BOTH));
browser.setSize(800, 600);
browser.setUrl("http://www.eclipse.org");
shell.open();
}
});
}
});
mainPanel.add(new JTextField("a JTextField"));
mainPanel.add(launchBrowserButton);
mainFrame.getContentPane().add(mainPanel, BorderLayout.CENTER);
mainFrame.pack();
mainFrame.setVisible(true);
}
});
display.addListener(SWT.Close, new Listener() {
public void handleEvent(Event event) {
EventQueue.invokeLater(new Runnable() {
public void run() {
Frame[] frames = JFrame.getFrames();
for (int i = 0; i < frames.length; i++) {
frames[i].dispose();
}
}
});
}
});
while (!display.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
}
}
If the desktop is not zoomed the application starts just fine and there is no issue.
The stack of the blocked event dispatch thread looks like this:
CWindow._setVisible(long, boolean, boolean, int, boolean, int, int, boolean) line: not available [native method]
CFrame.setVisible(boolean) line: 111
CFrame(CComponent).show() line: 219
JFrame(Component).show() line: 1530
JFrame(Window).show() line: 871
JFrame(Component).show(boolean) line: 1563
JFrame(Component).setVisible(boolean) line: 1515
JFrame(Window).setVisible(boolean) line: 841
Does anyone have any idea on how to work around this? Thanks.
EDIT - WORKAROUND 1
If I enclose the setVisible in asyncExec and don't use SWT_AWT shell but plain shell like this :
....
display.asyncExec(new Runnable() {
@Override
public void run() {
mainFrame.pack();
mainFrame.setVisible(true);
});
....
launchBrowserButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
display.asyncExec(new Runnable() {
public void run() {
Shell shell = new Shell(display);
shell.setSize(800, 600);
Browser browser = new Browser(shell, SWT.NONE);
...
}
});
}
});
it seems to work for this simple example but in my application is still hangs on some event that is being dispatched in EDQ, so is not a solution....
WORKAROUND 2
If I replace the EventQueue to dispatch events in Thread0 it also work for the small example, it successfully staring my complex application as well but later on there are quite some other random bugs from this queue replacement
...
EventQueue eventQueue = Toolkit.getDefaultToolkit().getSystemEventQueue();
eventQueue.push(new MyEDQ());
...
class MyEQD extends EventQueue {
@Override
protected void dispatchEvent( AWTEvent arg0) {
final AWTEvent event = arg0;
A.display.asyncExec(new Runnable() {
@Override
public void run() {
MyEQD.super.dispatchEvent(event); }
});
}
}
}
...
So still anyone has any idea on how to solve this synchronization problem between Thread0 and EventDispatchThread more gracefully so I don't run into other issues?
Upvotes: 2
Views: 286