JDK-4109702 : requestFocus() caused windows "vibrating"
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.4.2,5.0,6
  • Priority: P5
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_nt,windows_2000
  • CPU: x86,itanium
  • Submitted: 1998-02-05
  • Updated: 2010-12-30
Related Reports
Duplicate :  
Duplicate :  
Description
Name: diC59631			Date: 02/05/98


Symptoms: AWT windows "flash" or "vibrate" rapidly and are hard to close

To reproduce the problem:
[1] compile the enclosed awtwin.java
[2] run "appletviewer awtwin.html"
[3] click the AWT window 5 times quickly to create 5 windows

The problem will not occur if clicked slowly, 
i.e. one click after one window is created.

What appears to be happening is that the AWT is not detecting that a window
has been activated if focus is requested and there is a processing load prior
to launching the window.

================ awtwin.html ================
<HTML>
<HEAD>
<TITLE> AWT Window Problem Demonstration </TITLE>
</HEAD>
<BODY>
<APPLET CODE="awtwin.class" WIDTH=300 HEIGHT=350>
</APPLET>
</BODY>
</HTML>



================ awtwin.java ================
// Test of requestFocus() calls within multiple windows.
//

import java.awt.*;
import java.awt.event.*;
import java.applet.*;

public class awtwin extends Applet implements MouseListener {
 static int Count = 0;
 static final String maxed_out = new String("Maximum of 5 test windows.");
 static final int margin = 100;
 FontMetrics fm;
 Dimension d;
 Label l;

 public void init() {
  setLayout(new BorderLayout());
  add ("North", l = new Label("Demonstration of AWT Window problem.", Label.CENTER));
  addMouseListener(this);
 }

 public void addNotify() {
  super.addNotify();
  Font f = getFont();
  if (f != null)
   fm = getFontMetrics(f);
 }

 public void mouseClicked (MouseEvent evt) {
  if (Count < 5) {
   Count++;
   String Title = new String("Test Window " + Count);
   int wd = fm.stringWidth(Title) + margin;
   d = new Dimension(wd, wd);
   TestWindow tw = new TestWindow(Title, d);
   tw.show();
   // Addition of the line below increased the chances of inducing the problem significantly.
   // This suggests a timing problem.
   try { Thread.sleep(1000); } catch ( InterruptedException e) { ; }
   }
   else l.setText(maxed_out);
 }

 public void mouseEntered  (MouseEvent evt) { }
 public void mouseExited   (MouseEvent evt) { }
 public void mousePressed  (MouseEvent evt) { }
 public void mouseReleased (MouseEvent evt) { }

 class TestWindow extends Frame implements WindowListener {

  public TestWindow(String Title, Dimension d) {
   super (Title);
   setSize(d);
   addWindowListener(this);
  }

  public void windowActivated(WindowEvent e) {
   requestFocus();
  }

  public void windowClosed(WindowEvent e) {
  }

  public void windowClosing(WindowEvent e) {
   this.dispose();
   Count--;
  }

  public void windowDeactivated(WindowEvent e) {  }

  public void windowDeiconified(WindowEvent e) {  }

  public void windowIconified(WindowEvent e) {  }

  public void windowOpened(WindowEvent e) {  }

 }

}
(Review ID: 24619)
======================================================================

Name: skT88420			Date: 08/20/99


We have been experiencing a whole load of problems with windowActivated
and JRE 1.2.2.

1. With some programs which subclass Frame or Dialog, when launched
   from another Frame or Dialog, focus is not given to a component
   which requests it from windowActivated.

2. A requestFocus, issued from windowActivated, only appears to work
   once, the first time it is called; that is when it does work.

The following code demonstrates this. When the windows Activate2 and
Activate3 appear, click in the second field, lose focus on the Frame
by clicking on another window, gain focus back on the first window by
clicking on it. Focus remains on the second field, even though the
windowActivated method is executed and it explicitly requests focus on
the first field.

The example code will also show a windows focus war if a certain line,
in Activate2, is uncommented.

import java.awt.*;
import java.awt.event.*;

class ActivateTest extends Frame
{

  TextField tf = new TextField();

  public ActivateTest( String name)
  {
    super( name);
    tf.setColumns( 20);
    add( tf);

    addWindowListener(
      new WindowAdapter()
      {
         public void windowActivated( WindowEvent we)
         {
            ///tf.requestFocus();
         }

         public void windowOpened( WindowEvent we)
         {
            Activate2 at2 = new Activate2("Activate2");
            at2.pack();
            at2.show();

         }

         public void windowClosing( WindowEvent we)
         {
           dispose();
         }
      }
    );

  }

  public static void main(String argv[] )
  {
   ActivateTest at = new ActivateTest("ActivateTest");

   at.pack();
   at.show();
  }
}

import java.awt.*;
import java.awt.event.*;

class Activate2 extends Frame
{

  TextField tf = new TextField();
  TextField tf2 = new TextField();

  public Activate2( String name)
  {
    super(name);

    setLayout( new FlowLayout());
    tf.setColumns( 20);

    tf2.setColumns( 20);
    tf2.setText( "Hello");

    add( tf);
    add( tf2);

    addWindowListener(
      new WindowAdapter()
      {
         public void windowActivated( WindowEvent we)
         {
            System.out.println("Activate2 Activated and Requesting focus");
            //
            //tf should always get focus when window activated. Not with JRE 1.2.2
            //Only first time this is executed does the field in question normally,
            //but not always, get focus.
            tf.requestFocus();
            System.out.println("Focus owner post requestFocus: " + getFocusOwner().toString());
         }

         public void windowClosing( WindowEvent we)
         {
          dispose();
         }

         public void windowOpened( WindowEvent we)
         {
           Activate3 at3 = new Activate3( "Activate3");
           at3.pack();
           at3.show();
           //
           //Uncomment the next line to start vibrator. In JRE 1.1.3, focus wars with
           //all three windows until one is killed. In JRE 1.2.2 focus wars with all three
           //windows until one is minimised!! Then focus wars stop, even when minimised
           //window is maximised!?!?!
           ///tf.requestFocus();
         }
      }
    );

  }

}

import java.awt.*;
import java.awt.event.*;

class Activate3 extends Frame
{

  TextField tf = new TextField();
  TextField tf2 = new TextField();

  public Activate3( String name)
  {
    super(name);

    setLayout( new FlowLayout());
    tf.setColumns( 20);

    tf2.setColumns( 20);
    tf2.setText( "Act3");

    add( tf);
    add( tf2);

    addWindowListener(
      new WindowAdapter()
      {
         public void windowActivated( WindowEvent we)
         {
            System.out.println("Activate3 Activated and Requesting focus");
            tf.requestFocus();
            System.out.println("Activate3 Focus owner post requestFocus: " + getFocusOwner().toString());
         }

         public void windowClosing( WindowEvent we)
         {
          dispose();
         }
      }
    );

  }

}
(Review ID: 94162)
======================================================================
###@###.### 10/4/04 16:42 GMT

Comments
EVALUATION there is a good test for reproducing this problem: java/awt/Focus/ActivateFocusTest/ActivateFocusTest.html also see 4880721 to find how to modify the test to make it easy to reproduce the problem.
2007-05-15

EVALUATION General focus rewrite has happened though the problem still exists. Reproduced with Mustang b53 on WinXP.
2005-09-27

CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mustang
2004-09-17

WORK AROUND Name: diC59631 Date: 02/05/98 A workaround is to move all requestFocus() code from the windowActivated() method to windowOpened(). This results in a brief flickering of the display as each window is opened, which stops immediately. The windowOpened() method is supposed to be called only once on a given window. ====================================================================== Name: skT88420 Date: 08/20/99 Most of the time, it is possible to move the requestFocus to the windowOpened method to force focus onto the component. NOTE: Checks were made to ensure the component was visible/showing when the windowActivated method was executed (Review ID: 94162) ====================================================================== Name: osR10079 Date: 01/18/2002 To specify component which will receive focus after window activation in 1.4 user can: 1. use Component.requestFocusInWindow() instead of Component.requestFocus(); 2. make his own FocusTraversalPolicy which will report required default component for the window. ###@###.### 18 Jan 2002 ======================================================================
2004-09-17

EVALUATION Not reproducible in 1.1.7 or 1.2. mike.bronson@eng 1998-07-14 This problem occurs only on Windows. It is caused by WINDOW_ACTIVATED events getting queued up in the java EventQueue together with more than one window making a call to requestFocus() from within windowActivated() (ie. making a call to get the focus immediately after the window's got the focus). The solution is to make remove any preceeding WINDOW_ACTIVATED events in the EventQueue when a new WINDOW_ACTIVATED event is posted onto the queue, on the basis that any window receiving focus notification by a preceeding WINDOW_ACTIVATED event will only have the focus for a negligible amount of time, & therefore the elimination of the event will not have a negative impact on the system as a whole. neil.richards@eng 1998-09-28 ----------------------------------------------------------------------------- jeff.dunn@Eng 1998-10-02 Removing WINDOW_ACTIVATED events makes me very nervous. activated and deactivated events must arrive in pairs and in the correct order. Realistically, we have not properly defined what happens when Frame.requestFocus() in invoked. Does that mean that we want keyboard events to go to that Frame, or for the Frame to be activated. or both. Since one would assume that the application code is not trying to activate the window, because it is already active. It must be trying to get keyboard focus to the Frame itself, which is an unusual thing to do. If we define Frame.requestFocus() to mean "requestActivation()", then we must ignore the requestFocus() entirely, because the Frame is already active. In any case, I think removing WINDOW_ACTIVATED events is not the right thing to do. I'm getting a concensus on what exactly Frame.requestFocus() means, and then we'll figure out how to handle this. ----------------------------------------------------------------------------- This problem shows that it is dangerous to honor WM_AWT_COMPONENT_SETFOCUS messages (sent just after activation notification & in requestFocus()) if java's view of what is the active window is not in sync with what the real active window is. Therefore a track needs to be kept of what *java believes* is the active window, & extra checking added to the processing for WM_AWT_COMPONENT_SETFOCUS to selectively ignore focus requests when the system is in this condition. (This in part mimics the behaviour of actual java events received on Solaris, where the problem does not exist). For similar reasons, a track of what java believes the window with focus is needs to be kept in order to filter out focus requests made when that is inconsistant with the actual window is (ie. to avoid the possibility of focus looping). As a result of this screening, a focus request maybe received for a window which already holds the native focus. In this case, an explicit WM_SETFOCUS message needs to be sent to the window (a call to ::SetFocus() in this instance would be filtered by the OS), unless the system has already received notification via a WM_SETFOCUS message (ie. a WM_SETFOCUS message has been received but the corresponding FOCUS_GAINED event is still in the java event queue). This needs to be tracked by a third variable, which records which window the VM has been notified has the (native) focus. neil.richards@eng 1998-11-18 Verified the problem as fixed, however the regression test is not up to spec. Will notify the awt team, but the bug is fixed. Verified via direct use of java. Causes error using JavaTest 2.0. john.s.lee@Eng 1999-01-21 Seems this fix breaks 4140890. Re-opening the bug for now... robi.khan@eng 1999-02-09 Decomitting fix for 1.1.8 because it causes regression. robi.khan@eng 1999-03-01 Removed fix entirely, since other regressions have been traced back to it. Will have to wait for general focus rewrite in 1.3. robi.khan@eng 1999-03-03 ###@###.### 10/6/04 12:35 GMT
1999-03-03

SUGGESTED FIX (diff src/win32/sun/windows/awt_Window.cpp 1.54 1.55) 678,679c678,680 < ASSERT(peer != NULL); < AwtComponent * component = PDATA(AwtComponent, peer); --- > > if ((peer != NULL) && (unhand(peer)->pData != 0)) { > AwtComponent * component = PDATA(AwtComponent, peer); 681,686c682,688 < // Request the focus, passing the containing window as the wParam so < // SetFocus() will not be called (causing unwanted activation) if < // the components ancestor top-level window is not active < // (see AwtComponent handling of WM_AWT_COMPONENT_SETFOCUS) < WPARAM wParam = (WPARAM)window->GetHWnd(); < VERIFY(::PostMessage(component->GetHWnd(), WM_AWT_COMPONENT_SETFOCUS, wParam, 0)); --- > // Request the focus, passing the containing window as the wParam so > // SetFocus() will not be called (causing unwanted activation) if > // the components ancestor top-level window is not active > // (see AwtComponent handling of WM_AWT_COMPONENT_SETFOCUS) > component->SendMessage(WM_AWT_COMPONENT_SETFOCUS, > (WPARAM)window->GetHWnd()); > } (diff src/win32/sun/windows/awt_Component.h 1.72 1.73) 215a216,219 > INLINE HWND GetActiveHWnd() { return m_activeHWnd; } > INLINE HWND GetFocusHWnd() { return m_focusHWnd; } > INLINE HWND GetNativeFocusHWnd() { return m_nativeFocusHWnd; } > 260a265,266 > void SendWPostponedMessageEvent(UINT message, WPARAM wParam=0, LPARAM lParam=0); > 352a359,360 > virtual MsgRouting WmAwtComponentSetFocus(HWND windowHWnd); > 398a407,409 > static HWND m_activeHWnd; > static HWND m_focusHWnd; > static HWND m_nativeFocusHWnd; (diff src/win32/sun/windows/awt_Frame.cpp 1.49 1.50) 174a175 > SendWPostponedMessageEvent(WM_AWT_COMPONENT_ACTIVATE, (WPARAM)FALSE); 178a180 > SendWPostponedMessageEvent(WM_AWT_COMPONENT_ACTIVATE, (WPARAM)TRUE); (diff src/win32/sun/windows/awtmsg.h 1.26 1.27) 2c2 < * @(#)awtmsg.h 1.26 98/08/25 --- > * @(#)awtmsg.h 1.27 98/11/18 47a48,49 > #define WM_AWT_COMPONENT_ACTIVATE AWT_MSG_BASE+26 > #define WM_AWT_COMPONENT_GOTFOCUS AWT_MSG_BASE+27 (diff src/win32/sun/windows/awt_Component.cpp 1.173 1.174) 39a40 > #include <sun_awt_windows_WPostponedMessageEvent.h> 57a59,61 > HWND AwtComponent::m_activeHWnd = NULL; > HWND AwtComponent::m_focusHWnd = NULL; > HWND AwtComponent::m_nativeFocusHWnd = NULL; 747,760c751,752 < if (wParam != NULL) { < if ( ((HWND) wParam) == ::GetActiveWindow()) { < ::SetFocus(GetHWnd()); < } else { < // Don't call SetFocus if our top-level window is not < // active since SetFocus would activate it. < ::SendMessage((HWND) lParam, WM_KILLFOCUS, (WPARAM)GetHWnd(), 0); < ::SendMessage(GetHWnd(), WM_SETFOCUS, lParam, 0); < } < } else { < ::SetFocus(GetHWnd()); < } < mr = mrConsume; < break; --- > mr = WmAwtComponentSetFocus((HWND)wParam); > break; 761a754,769 > case WM_AWT_COMPONENT_ACTIVATE: > if (wParam) { > m_activeHWnd = GetHWnd(); > } else if (m_activeHWnd == GetHWnd()) { > m_activeHWnd = NULL; > } > break; > > case WM_AWT_COMPONENT_GOTFOCUS: > if (wParam) { > m_focusHWnd = GetHWnd(); > } else if (m_focusHWnd == GetHWnd()) { > m_focusHWnd = NULL; > } > break; > 836a845,846 > m_nativeFocusHWnd = GetHWnd(); > SendWPostponedMessageEvent(WM_AWT_COMPONENT_GOTFOCUS, (WPARAM)TRUE); 856a867,870 > if (m_nativeFocusHWnd == GetHWnd()) { > m_nativeFocusHWnd = NULL; > } > SendWPostponedMessageEvent(WM_AWT_COMPONENT_GOTFOCUS, (WPARAM)FALSE); 1717a1732,1770 > MsgRouting AwtComponent::WmAwtComponentSetFocus(HWND windowHWnd) > { > BOOL javaWindowActive; //Java thinks it has an active window. > BOOL activeWindowInSync; //Java & native think the same window's active. > BOOL focusWindowInSync; //Java & native think the same window's got focus. > BOOL gotNativeFocus; //Native already has focus. > BOOL gotNativeFocusMsg; //VM already notified of native having focus. > BOOL honorSetFocus; //Is VM in a state/needs to honor focus request. > > javaWindowActive = (GetActiveHWnd() != NULL); > activeWindowInSync = (GetActiveHWnd() == ::GetActiveWindow()); > focusWindowInSync = (GetFocusHWnd() == ::GetFocus()); > gotNativeFocus = (GetHWnd() == ::GetFocus()); > gotNativeFocusMsg = (GetHWnd() == GetNativeFocusHWnd()); > honorSetFocus = ((!javaWindowActive || (activeWindowInSync && > focusWindowInSync)) && > !(gotNativeFocus && gotNativeFocusMsg)); > > if (honorSetFocus) { > BOOL windowHWndActive; //windowHWnd exists & is active. > BOOL normalSetFocus; //Use ::SetFocus() to set focus. > > windowHWndActive = > ((windowHWnd != NULL) && (windowHWnd == ::GetActiveWindow())); > normalSetFocus = > ((windowHWndActive || javaWindowActive) && !gotNativeFocus); > > if (normalSetFocus) { > ::SetFocus(GetHWnd()); > } else if (gotNativeFocus) { > ::SendMessage(GetHWnd(), WM_SETFOCUS, (WPARAM)GetHWnd(), 0); > } else { > ::SendMessage(::GetFocus(), WM_KILLFOCUS, (WPARAM)GetHWnd(), 0); > ::SendMessage(GetHWnd(), WM_SETFOCUS, (WPARAM)::GetFocus(), 0); > } > } > return mrConsume; > } > 1840a1894,1914 > void AwtComponent::SendWPostponedMessageEvent(UINT message, WPARAM wParam, LPARAM lParam) > { > static ClassClass* classEvent = NULL; > if (classEvent == NULL) { > char* clsName = "sun/awt/windows/WPostponedMessageEvent"; > classEvent = FindStickySystemClass(EE(), clsName, TRUE); > if (classEvent == NULL) { > SignalError(0, JAVAPKG "ClassNotFoundException", clsName); > return; > } > ASSERT(classEvent); > } > > Hsun_awt_windows_WPostponedMessageEvent* hEvent = > (Hsun_awt_windows_WPostponedMessageEvent*) > execute_java_constructor(EE(), NULL, classEvent, "(Ljava/lang/Object;Lsun/awt/windows/WObjectPeer;III)", GetTarget(), GetPeer(), (long)message, (long)wParam, (long)lParam); > ASSERT(!exceptionOccurred(EE())); > ASSERT(hEvent != NULL); > SendEvent((Hjava_awt_AWTEvent*)hEvent); > } > 2293c2367,2368 < VERIFY(::PostMessage(p->GetHWnd(), WM_AWT_COMPONENT_SETFOCUS, 0, 0)); --- > > p->SendMessage(WM_AWT_COMPONENT_SETFOCUS); 2573a2649,2657 > > void > sun_awt_windows_WPostponedMessageEvent_dispatchImpl(Hsun_awt_windows_WPostponedMessageEvent* self, Hsun_awt_windows_WObjectPeer* peer, long message, long wParam, long lParam) > { > if ((peer != NULL) && (unhand(peer)->pData != 0)) { > AwtComponent* p = PDATA(AwtComponent, peer); > ::SendMessage((HWND)p->GetHWnd(), (UINT)message, (WPARAM)wParam, (LPARAM)lParam); > } > } (diff src/win32/sun/sun/awt/windows/WPostponedMessageEvent.java 1.0 1.1) 0a1,39 > /* > * @(#)WPostponedMessageEvent.java 1.1 98/11/20 > * > * Copyright 1995-1998 by Sun Microsystems, Inc., > * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. > * All rights reserved. > * > * This software is the confidential and proprietary information > * of Sun Microsystems, Inc. ("Confidential Information"). You > * shall not disclose such Confidential Information and shall use > * it only in accordance with the terms of the license agreement > * you entered into with Sun. > */ > package sun.awt.windows; > > import java.awt.AWTEvent; > import java.awt.peer.ActiveEvent; > > class WPostponedMessageEvent extends AWTEvent implements ActiveEvent > { > private WObjectPeer peer; > private int message; > private int wParam; > private int lParam; > > public WPostponedMessageEvent(Object target, WObjectPeer peer, int message, int wParam, int lParam) { > super(target, 0); > this.peer = peer; > this.message = message; > this.wParam = wParam; > this.lParam = lParam; > } > > public void dispatch() { > dispatchImpl(peer, message, wParam, lParam); > } > > private native void dispatchImpl(WObjectPeer peer, int message, int wParam, int lParam); > } (diff build/win32/sun/winawt/classes.mk 1.32 1.33) 64a65 > $(AWT_CLASSES)\windows\WPostponedMessageEvent.class 189a191 > sun.awt.windows.WPostponedMessageEvent ===== Testcase: (diff test/java/awt/Frame/RequestFocusVibration/RequestFocusVibration.html 1.0 1.1) 0a1,5 > <html> > <body> > <applet code=RequestFocusVibration.class width=300 height=350></applet> > </body> > </html> (diff test/java/awt/Frame/RequestFocusVibration/RequestFocusVibration.java 1.0 1.1) 0a1,117 > /* > * Licensed Materials - Property of IBM > * > * RequestFocusVibration.java > * > * (C) Copyright IBM Corporation 1998 All Rights Reserved. > * > * US Government Users Restricted Rights - Use, duplication or disclosure > * restricted by GSA ADP Schedule Contract with IBM Corp. > */ > > /* 1.1 98/11/18 > @bug 4109702 > @summary Test of requestFocus() calls within multiple windows > @run applet/manual=yesno/timeout=30 RequestFocusVibration.html > @author Neil Richards > */ > > import java.awt.*; > import java.awt.event.*; > import java.applet.*; > > public class RequestFocusVibration extends Applet implements MouseListener, WindowListener, Runnable { > int count; > Frame target; > int fWidth; > > public RequestFocusVibration() { > this(null); > } > > public RequestFocusVibration(Frame f) { > target = f; > fWidth = 0; > count = 0; > } > > public void init() { > setLayout(new BorderLayout()); > Panel p = new Panel(); > add("North", p); > setBackground(Color.red); > p.setLayout(new GridLayout(0,1,20,0)); > p.setBackground(Color.white); > p.add(new Label("Click in the red area 3 times quickly.", Label.LEFT)); > p.add(new Label("This will create 3 new windows.", Label.LEFT)); > p.add(new Label(" ", Label.LEFT)); > p.add(new Label("If these windows \"flash\" or \"vibrate\"", Label.LEFT)); > p.add(new Label("rapidly, the test has failed.", Label.LEFT)); > p.add(new Label(" ", Label.LEFT)); > p.add(new Label("The windows should be destroyed after 10", Label.LEFT)); > p.add(new Label("seconds, allowing you to press the pass", Label.LEFT)); > p.add(new Label("or fail button.", Label.LEFT)); > addMouseListener(this); > } > > public void mouseClicked (MouseEvent evt) { > synchronized(this) { > if (count < 3) { > count++; > > String title = new String("Window " + count); > > if (fWidth == 0) { > fWidth = getFontMetrics(getFont()).stringWidth(title) + 100; > } > Rectangle r = getBounds(); > > Frame f = new Frame(title); > f.setSize(new Dimension(fWidth, fWidth)); > f.setLocation(r.x + r.width + 10, r.y + > ((count - 1) * 30)); > f.addWindowListener(this); > f.show(); > > Thread t = new Thread(new RequestFocusVibration(f)); > t.start(); > > // Addition of the line below increased the chances of inducing the > // problem significantly. This suggests a timing problem. > try { > Thread.sleep(1000); > } catch ( InterruptedException e) {} > } > } > } > > public void mouseEntered (MouseEvent evt) {} > public void mouseExited (MouseEvent evt) {} > public void mousePressed (MouseEvent evt) {} > public void mouseReleased (MouseEvent evt) {} > > public void windowActivated(WindowEvent e) { > e.getWindow().requestFocus(); > } > > public void windowClosing(WindowEvent e) { > e.getWindow().dispose(); > } > > public void windowClosed(WindowEvent e) { > count--; > } > public void windowDeactivated(WindowEvent e) {} > public void windowDeiconified(WindowEvent e) {} > public void windowIconified(WindowEvent e) {} > public void windowOpened(WindowEvent e) {} > > public void run(){ > try { > Thread.currentThread().sleep(10000); > } catch (InterruptedException e) {} > target.dispose(); > } > } > > neil.richards@eng 1998-11-20
1998-11-20