United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6770457 Using ToolTips causes inactive app window to exhibit active window behavior
JDK-6770457 : Using ToolTips causes inactive app window to exhibit active window behavior

Details
Type:
Bug
Submit Date:
2008-11-12
Status:
Closed
Updated Date:
2011-02-16
Project Name:
JDK
Resolved Date:
2009-05-15
Component:
client-libs
OS:
windows_xp,windows_2000
Sub-Component:
java.awt
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
6u10,6u12
Fixed Versions:
6u14 (b02)

Related Reports
Backport:
Backport:
Duplicate:
Duplicate:
Relates:
Relates:
Relates:
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
Java Plug-in 1.6.0_10
Using JRE version 1.6.0_10 Java HotSpot(TM) Client VM

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 [Version 5.00.2195]



EXTRA RELEVANT SYSTEM CONFIGURATION :
Problem seems to occur only on Windows OS -- I cannot reproduce the problem on Solaris.   Problem occurred with JRE1.6.0_07, and earlier 1.6 releases, as well as 1.6.0_10).  Problem does not occur with Java 1.5 (maybe because tooltips are not shown for not-focussed applets in Java 1.5?)

I have produced the problem with Firefox 2.0.0.17 and Internet Explorer 6.0 SP1

A DESCRIPTION OF THE PROBLEM :
When an applet window has focus and is positioned over an underlying applet embedded in the web browser, moving the mouse over the not-focussed applet and displaying tooltips causes the not-focussed applet (web browser window) to come to the front, thus hiding the focussed applet window.

Problem only occurs on Windows OS -- I do not see the problem on Solaris.

This problem appears to be a regression in Java 1.6 from Bug 4148057 which was fixed in Java 1.5.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile test case program, and run in web browser with test case HTML, using Java 1.6 plugin.

There will be a JTable applet in the web browser, and a little popup window named W2 with a JButton in it.  Position the W2 window over the JTable, and click the button a couple times (i.e., verify that the W2 window has focus and is in front of the JTable.

Now move the mouse over the JTable.  Tooltips will display for the items in the JTable.  When you move the mouse over an item where the tooltip extends beyond the bounds of the JTable, the Web browser window with the JTable in it will come to the front, hiding W2. (The tooltip for "Function1"  in Col3 is very long, so it works -- also the tooltip for any other cell in the JTable will work if it extends beyond the bounds of the JTable.)

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
W2 should stay on top (visible over the Web browser window with the JTable no matter where you move the mouse over the JTable (so long as you don't click the mouse to change focus, of course).
ACTUAL -
When mouse moved over a table cell where the tooltip extends beyond the bounds of the table, the Web browser window comes to the top and W2 gets hidden.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
No error messages.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
HTML to run test case:

<HTML>
<HEAD><TITLE>Windows tooltip focus problem</TITLE></HEAD>
<BODY BGCOLOR="#FFFFFF">

<APPLET CODE = TooltipTest  ARCHIVE = TTT.jar WIDTH = 454 HEIGHT = 204>

</APPLET>
</BODY>
</HTML>

------------------

Test case source code:

//import java.awt.FlowLayout;
import javax.swing.*;
import javax.swing.table.*;

import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;

public class TooltipTest extends JApplet {


String[] columnNames = {"Col1",
                        "Col2",
                        "Col3",
                        "Col4",
                        "Col5"};

Object[][] data = null;


  public void init() {

      data = new Object [40][5];
      for (int ix = 0; ix < 40; ++ix) {
          data[ix][0] = "Name1-" + ix;
          data[ix][1] = "Name2-" + ix;
          data[ix][2] = "Function" + ix;
          data[ix][3] = "";
          data[ix][4] = "Name5-" + ix;
      }
      JTable t = new JTable( data, columnNames);
      t.setDefaultRenderer(String.class, new ObjectRenderer());
      t.setDefaultRenderer(Object.class, new ObjectRenderer());

       JScrollPane jsp = new JScrollPane(t);
      setSize(454, 204);

       jsp.setPreferredSize(new Dimension(450, 200));

  //    setLayout(new FlowLayout());
      GridBagLayout layout = new GridBagLayout();
      GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 1;
        gbc.anchor = GridBagConstraints.SOUTHEAST;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.insets = new Insets( 2,2,2,2 ) ;
      
      getContentPane().setLayout(layout);
      layout.setConstraints(jsp, gbc);
      getContentPane().add(jsp);
//add(jsp);

      //setVisible(true);
        System.out.println("Version 1.33 " + getClass().getName());
        JFrame frame2 = new JFrame("W2");
         JButton buttonX = new JButton("Button TESTX");
        buttonX.setToolTipText("Tooltip TESTX");
        buttonX.addActionListener(new ActionListener() {
              public void actionPerformed(ActionEvent ae) {
                  System.out.println("buttonX clicked");
              }

        });
       frame2.getContentPane().setLayout(new FlowLayout());
       frame2.getContentPane().add(buttonX);
        frame2.setSize(200, 200);
        frame2.setLocation(50, 50);
        frame2.setVisible(true);
  }

   static class ObjectRenderer extends DefaultTableCellRenderer {
    	public ObjectRenderer(){
    		super();
    	}
  	
	    public Component getTableCellRendererComponent(JTable table, Object value,
						       boolean isSelected, boolean hasFocus, int row, int column) {
			super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

		//    if (isSelected)
	        //    setBorder(BorderFactory.createMatteBorder(2,0,2,0,Color.black));
	        
	        //setOpaque(true);
	        String s = getText();
                if (s.equals("Function0")) s = "";   // This does not fail (SmWrappedToolTipUI creates the problem here)
                if (s.equals("Function1")) s =
          "very long tool tip test text very long tool tip test text very long tool tip test text very long tool tip test text ends here";
	        setToolTipText( s);
	        return this;
	    }
    }

}


---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
No workaround.

Release Regression From : 5.0
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.
Customer requested to add the following information
I've been doing more testing of this problem,
and I've noticed something *in addition to* what I
wrote in the CQ:

For the sample program, in the Bug Report, I wrote that if
the tooltip for a table cell extends beyond the
bounds of the table when the table is not the
focussed frame and it is behind the
little popup with the button which has focus, then
if you move the mouse over a cell in the table with a
tooltip that extends beyond the table frame, then
the table comes to the top even though the little
popup with the button has focus.

What I did not write in that the problem occurrs "in the
opposite direction", also: If the frame with the table has
focus and is in front, and if you move the mouse over the 
button in the popup, if the button's tooltip extends beyond its
frame, then the button popup panel comes to the front even
though it does not have focus, too.

This is a kind of "nit", but I think it
points out that the problem is not only with
tooltips for widgets embedded in a frame that
is embedded in the web browser, but the problem occurs for
other windows associated with the browser session
also.
Customer has done further testing and has
submitted another test program

More "good" news....

I did even more testing, and it looks like the
problem has nothing at all to do with using a
web browser.

I modified my Example program to run from the command
line and reproduced the problem.


C:\SAM80B130\CONSOLE\smarts\tomcat\webapps\webconsole>\jdk1.6.0_10\bin\j
avac TooltipTest.java

C:\SAM80B130\CONSOLE\smarts\tomcat\webapps\webconsole>\jdk1.6.0_10\bin\j
ava TooltipTest


Revised source file follows
TooltipTest.java
//import java.awt.FlowLayout;
import javax.swing.*;
import javax.swing.table.*;

import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;

public class TooltipTest extends JApplet {


String[] columnNames = {"Col1",
                        "Col2",
                        "Col3",
                        "Col4",
                        "Col5"};

Object[][] data = null;

  public static void main(String[] argv) {
      TooltipTest app = new TooltipTest();

      app.init();


  }


  public void init() {
      JFrame frame = new JFrame("W1");
      data = new Object [40][5];
      for (int ix = 0; ix < 40; ++ix) {
          data[ix][0] = "Name1-" + ix;
          data[ix][1] = "Name2-" + ix;
          data[ix][2] = "Function" + ix;
          data[ix][3] = "";
          data[ix][4] = "Name5-" + ix;
      }
      JTable t = new JTable( data, columnNames);
      t.setDefaultRenderer(String.class, new ObjectRenderer());
      t.setDefaultRenderer(Object.class, new ObjectRenderer());

       JScrollPane jsp = new JScrollPane(t);
      //frame.setSize(454, 204);
frame.setSize(600,400);

       jsp.setPreferredSize(new Dimension(450, 200));

  //    setLayout(new FlowLayout());
      GridBagLayout layout = new GridBagLayout();
      GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.gridwidth = 1;
        gbc.anchor = GridBagConstraints.SOUTHEAST;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.insets = new Insets( 2,2,2,2 ) ;
      
      frame.getContentPane().setLayout(layout);
      layout.setConstraints(jsp, gbc);
      frame.getContentPane().add(jsp);
//add(jsp);

      frame.setVisible(true);
        System.out.println("Version 3.00 " + getClass().getName());
        JFrame frame2 = new JFrame("W2");
         JButton buttonX = new JButton("Button TESTX");
        buttonX.setToolTipText("Tooltip TESTX");
        buttonX.addActionListener(new ActionListener() {
              public void actionPerformed(ActionEvent ae) {
                  System.out.println("buttonX clicked");
              }

        });
       frame2.getContentPane().setLayout(new FlowLayout());
       frame2.getContentPane().add(buttonX);
        frame2.setSize(200, 200);
        frame2.setLocation(50, 50);
        frame2.setVisible(true);
  }

   static class ObjectRenderer extends DefaultTableCellRenderer {
        public ObjectRenderer(){
                super();
        }
  
            public Component getTableCellRendererComponent(JTable table, Object value,
                                                       boolean isSelected, boolean hasFocus, int row, int column) {
                        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

                //    if (isSelected)
                //    setBorder(BorderFactory.createMatteBorder(2,0,2,0,Color.black));
                
                //setOpaque(true);
                String s = getText();
                if (s.equals("Function0")) s = "";   // This does not fail (SmWrappedToolTipUI creates the problem here)
                if (s.equals("Function1")) s =
          "very long tool tip test text very long tool tip test text very long tool tip test text very long tool tip test text ends here";
                setToolTipText( s);
                return this;
            }
    }

}

                                    

Comments
EVALUATION

This is similar to 6643769 but has a different root cause. It appears that the showing or hiding of the tooltip is causing a window activation to be processed by the applet's window hierarchy, including the AWT EmbeddedFrame containing it, and this causes the browser's window to be raised to the front. The Java Plug-In is not initiating the activation of the window; commenting out all calls to EmbeddedFrame.synthesizeWindowActivation() does not address the problem. Very plausibly the EmbeddedFrame class should not be bringing the window to the front upon window activation, or the tooltip code should not be causing window activations. Reassigning to classes_awt because the EmbeddedFrame behavior needs to be reconsidered, although work might also be needed in classes_swing.
                                     
2008-11-12
EVALUATION

In the attached test, the Swing's tooltip is shown, when the user movies the mouse over the table. The test works well if the table contains the tootip. But the test fails if the tooltip extends beyound the table - in this case, Swing uses heavyweight underlying window (javax.swing.Popup$HeavyWeightWindow) to show the tooltip outside the table. The underlying window is non-focusable and the parent of the window is the parent of the table (EmbeddedFrame). Swing's ToolTipManager shows the window and the native system places all window's hierarhy (including the EmbeddedFrame) at the top of the z-order. At the same time, 'W2' window at the bottom of the z-order still keeps the focus. Making the Swing's window parentless eliminates the problem.
                                     
2008-11-25
EVALUATION

There is a fix for the bug 6405841 which was intended for fixing the problem when the inactive window is placed at the top of the z-order. The fix for 6405841 introduces some changes in the awt_Window class. When someone creates an object of the "javax/swing/Popup$HeavyWeightWindow" class, the fix keeps the handle to the popup menu and catches all WM_WINDOWPOSCHANING notifications for any of the ancestors of the popup window. The fix sets SWP_NOZORDER flags for all such notifications, thus, all inactive still keeps the same place in the Z-order as before.

The handler for the WM_WINDOWPOSCHANING notifications works during period between WM_WINDOWPOSCHANING (SWP_SHOWWINDOW) for the popup window and WM_WINDOWPOSCHANED ( SWP_SHOWWINDOW) for the popup window. It's expected that all ancestor's windows are notified and all notifications are modified during the period. But my experiments show that there are other WM_WINDOWPOSCHANG(ING|ED) messages coming to the popup window (SWP_NOSIZE|SWP_NOMOVE) and other ancestor's notifications (during the period between the messages for the popup window) which place the ancestors above the active window. The fix for 6405841 should be enhanced to handle this case.
                                     
2008-12-03
EVALUATION

The issue is a regression of the Swing's fix for 6580930
(Swing Popups should overlap taskbar) integrated in 6u10 b05.
The fix motifies the popup window and makes the popup window always-on-top.
The diffs for the change is as below:
-------------------------------------------------------
--- Popup.java        10 17:33:34 2007

*** 210,219 ****
--- 210,220 ----
              setFocusableWindowState(false);
              setName("###overrideRedirect###");
              // Popups are typically transient and most likely won't benefit
              // from true double buffering.  Turn it off here.
              getRootPane().setUseTrueDoubleBuffering(false);
+             setAlwaysOnTop(true);   
          }
  
          public void update(Graphics g) {
              paint(g);
          }
---------------------------------------------------------

Later, AWT calls SetWindowPos(...,HWND_TOPMOST,...) for all always-on-top windows.
The code which triggets the messages is as below:
----------------------------------------------------------
-- awt_Component.cpp 

      case WM_AWT_SETALWAYSONTOP: {
        AwtWindow* w = (AwtWindow*)lParam;
        BOOL value = (BOOL)wParam;
        ::SetWindowPos(w->GetHWnd(), (value != 0 ? HWND_TOPMOST : HWND_NOTOPMOST),
                       0,0,0,0, SWP_NOMOVE|SWP_NOSIZE);
        break;
      }
-----------------------------------------------------------

The Swing's fix for 6580930 breaks AWT's fix for 6405841
and several WM_WINDOWPOSCHANING messages aren't covered by the AWT's fix.
The easiest way to fix the bug 6770457 is to ignore the ancestor's z-order
messages during the messages introduced by the Swing's fix (6580930)
but I'm not sure if such fix is safe and it won't introduce new bugs.
                                     
2008-12-09
SUGGESTED FIX

--- awt_Window.cpp      2008-12-29 16:56:21.000000000 +0300
***************
*** 2059,2065 ****
--- 2059,2074 ----
      w = (AwtWindow *)pData;
      if (::IsWindow(w->GetHWnd()))
      {
+         // 6770457: ignore z-order changes in parents' tree
+         if (w->IsRetainingHierarchyZOrder()) {
+             sm_retainingHierarchyZOrderInShow = w->GetHWnd();
+         }
+
          w->SendMessage(WM_AWT_SETALWAYSONTOP, (WPARAM)value, (LPARAM)w);
+
+         if (w->IsRetainingHierarchyZOrder()) {
+             sm_retainingHierarchyZOrderInShow = NULL;
+         }
      }
  ret:
      env->DeleteGlobalRef(self);
                                     
2008-12-29
EVALUATION

The suggested fix works fine in case of any stand-alone application (or the applet in appletviewer) but the problem still exists for the applet in the browser. The cause of the failure in case of the browser is that the browser's notifications go past all AWT routines.
                                     
2009-01-11
EVALUATION

SWP_NOOWNERZORDER flag (SetWindowPos API function):
Does not change the owner window's position in the Z order

We can use this flag for transient windows when we don't want to modify the z-order position of the owner windows. In this case the test works fine for the applet in the browser as well.
                                     
2009-01-27
SUGGESTED FIX

http://sa.sfbay.sun.com/projects/awt_data/6u14/6770457/
                                     
2009-01-27



Hardware and Software, Engineered to Work Together