In certain situation, ToolTipManager does not remove itself from component, registered as MouseMotionListener. The result is that more and more ToolTipManagers are registered on components, leaking memory and gradually downgrading performance. Reproduced on j2se 1.4.0 and 1.4.1, Windows 2000.
This problem appears when a window with affected component (tested with JTree) is not focused and user clicks on it. On mousePressed, ToolTipManager sets 'insideComponent' to null, so it does not know the component on which it is registered. And it is registered at the moment - it happened on mouseEntered - when user moved cursor over the component (before click). With mouse button release following immediately, mouseExited and mouseEntered events are generated. Now, ToolTipManager can't remove itself on mouseExited as normally because 'insideComponent' is null, but it adds itself again on mouseEntered.
This can be simply reproduced e.g. on two JTree components with tooltips placed in two JInternalFrame windows, then clicking between them (click on the JTrees). With each click there's one more ToolTipManager as MouseMotionListener added to JTree. You may try the following code, or attached zip file containg also hacked JDK classes printing some debug messages.
public class ToolTipManagerLeak extends javax.swing.JFrame {
public ToolTipManagerLeak() {
jDesktopPane1 = new javax.swing.JDesktopPane();
jInternalFrame1 = new javax.swing.JInternalFrame();
jTree1 = new javax.swing.JTree();
jInternalFrame2 = new javax.swing.JInternalFrame();
jTree2 = new javax.swing.JTree();
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent evt) {
exitForm(evt);
}
});
jInternalFrame1.setVisible(true);
jTree1.setToolTipText("1");
jInternalFrame1.getContentPane().add(jTree1, java.awt.BorderLayout.CENTER);
jInternalFrame1.setBounds(20, 20, 130, 160);
jDesktopPane1.add(jInternalFrame1, javax.swing.JLayeredPane.DEFAULT_LAYER);
jInternalFrame2.setVisible(true);
jTree2.setToolTipText("2");
jInternalFrame2.getContentPane().add(jTree2, java.awt.BorderLayout.CENTER);
jInternalFrame2.setBounds(210, 20, 130, 220);
jDesktopPane1.add(jInternalFrame2, javax.swing.JLayeredPane.DEFAULT_LAYER);
getContentPane().add(jDesktopPane1, java.awt.BorderLayout.CENTER);
pack();
java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
setSize(new java.awt.Dimension(400, 300));
setLocation((screenSize.width-400)/2,(screenSize.height-300)/2);
}
private void exitForm(java.awt.event.WindowEvent evt) {
System.exit(0);
}
public static void main(String args[]) {
new ToolTipManagerLeak().show();
}
private javax.swing.JInternalFrame jInternalFrame2;
private javax.swing.JTree jTree2;
private javax.swing.JInternalFrame jInternalFrame1;
private javax.swing.JDesktopPane jDesktopPane1;
private javax.swing.JTree jTree1;
}