The build solves all issues when you're using the default Look and Feels. I've found strange behavior still occurs when using the Substance Look and Feel. This only occurs when running the applet in the browser and not when running from an AppletViewer context.
Here's a test case to reproduce:
1. Load the applet
2. Select 'Focus' button in the debug internal frame
3. Select the game frame by clicking on the title bar (NOT the canvas)
4. Attempt to open the File menu.
5. Observe how the File menu stays collapsed.
package test;
import java.awt.Canvas;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.metal.MetalLookAndFeel;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.pushingpixels.substance.api.skin.SubstanceBusinessBlackSteelLookAndFeel;
public class CanvasFocusTest extends JApplet {
/**
*
*/
private static final long serialVersionUID = 2853176700479564421L;
private JMenuBar menuBar;
private Canvas canvas;
private Thread gameThread;
private boolean running;
private JInternalFrame createDebugFrame() {
JInternalFrame internalFrame = new JInternalFrame("Debug Frame");
internalFrame.setLayout(new FlowLayout(FlowLayout.CENTER));
internalFrame.setSize(400, 100);
internalFrame.setVisible(true);
JButton focus = new JButton("Focus");
focus.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
canvas.setFocusable(true);
}
});
internalFrame.add(focus);
JButton unfocus = new JButton("Unfocus");
unfocus.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
canvas.setFocusable(false);
}
});
internalFrame.add(unfocus);
JButton metal = new JButton("Metal");
metal.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switchMetal();
}
});
internalFrame.add(metal);
JButton substance = new JButton("Substance");
substance.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
switchSubstance();
}
});
internalFrame.add(substance);
return internalFrame;
}
private JInternalFrame createGameFrame() {
JInternalFrame canvasFrame = new JInternalFrame("Game Frame");
canvasFrame.setSize(800, 600);
canvasFrame.setLocation(80, 80);
canvasFrame.setVisible(true);
canvas = new Canvas() {
@Override
public final void addNotify() {
super.addNotify();
startLWJGL();
}
@Override
public final void removeNotify() {
stopLWJGL();
super.removeNotify();
}
};
canvasFrame.add(canvas);
canvas.setSize(canvasFrame.getContentPane().getSize());
canvas.setFocusable(true);
canvas.requestFocus();
canvas.setIgnoreRepaint(true);
Thread thread = new Thread() {
@Override
public void run() {
while (true) {
while (!Mouse.isCreated()) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while (Mouse.next()) {
int wheelD = Mouse.getDWheel();
if (wheelD != 0) {
System.out.println("" + wheelD);
}
}
}
}
};
thread.start();
return canvasFrame;
}
protected void gameLoop() {
while (running) {
Display.sync(60);
Display.update();
}
Display.destroy();
}
@Override
public void init() {
}
protected void initGL() {
}
private void loadSwing() {
switchSubstance();
menuBar = new JMenuBar();
JMenu file = new JMenu("File");
file.add(new JMenuItem("Item 1"));
file.add(new JMenuItem("Item 2"));
file.add(new JMenuItem("Item 3"));
menuBar.add(file);
setJMenuBar(menuBar);
JDesktopPane desktop = new JDesktopPane();
this.add(desktop);
JInternalFrame canvasFrame = createGameFrame();
desktop.add(canvasFrame);
JInternalFrame debugFrame = createDebugFrame();
desktop.add(debugFrame);
this.setSize(1024, 768);
}
@Override
public void start() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
loadSwing();
}
});
}
public void startLWJGL() {
gameThread = new Thread() {
@Override
public void run() {
running = true;
try {
Display.setParent(canvas);
Display.create();
initGL();
} catch (LWJGLException e) {
e.printStackTrace();
return;
}
gameLoop();
}
};
gameThread.start();
}
private void stopLWJGL() {
Display.destroy();
}
protected void switchMetal() {
try {
UIManager.setLookAndFeel(new MetalLookAndFeel());
UIManager.getLookAndFeelDefaults().put("ClassLoader", getClass().getClassLoader());
SwingUtilities.updateComponentTreeUI(this);
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
}
protected void switchSubstance() {
try {
UIManager.setLookAndFeel(new SubstanceBusinessBlackSteelLookAndFeel());
UIManager.getLookAndFeelDefaults().put("ClassLoader", getClass().getClassLoader());
SwingUtilities.updateComponentTreeUI(this);
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
}
}
The Substance L&F jars can be found here:
http://grepcode.com/snapshot/repo1.maven.org/maven2/com.github.insubstantial/substance/7.2.1/