JDK-4199374 : Component.requestFocus() fails for components on JWindow.
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.2.0,1.2.2
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 1998-12-22
  • Updated: 2001-07-02
  • Resolved: 2000-10-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other Other Other
1.3.0_02 02Fixed 1.3.1Fixed 1.4.0Fixed
Related Reports
Relates :  
Relates :  
Description

Name: krT82822			Date: 12/22/98


Focus management appears to be handled differently in JWindow and JFrame as the following example shows.  The sample code attempts to
create a JFrame with a JButton that, when pressed, creates a JWindow with a JTextField.  It then attempts to give the JTextField focus immediately
after it is displayed.

In practice, the field never receives focus.  Trying to set focus to the window yields interesting, but unhelpful results (the field gets and loses focus
before the window does.)  Setting focus on a timer doesn't do the trick.  I also have a nasty workaround that works on Win32 but not Solaris, but that
really isn't any better.

The attempt to transfer focus works flawlessly if the field is placed in a JFrame as implemented using the commented out code in the sample below,
so it seems clear that JWindow is somehow failing to provide proper focus management.

  import java.awt.event.*;
  import javax.swing.*;
  public class Test {
    public static void main(String args[]) {
      JFrame frame = new JFrame();
      JButton button = new JButton("Test");
      frame.getContentPane().add(button);
      frame.pack();

      frame.addFocusListener(new NoisyFocusListener("Frame"));
      button.addFocusListener(new NoisyFocusListener("Button"));

      button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          JWindow window = new JWindow();
  //        JFrame window = new JFrame();
          JTextField field = new JTextField("Edit Me!");
          window.getContentPane().add(field);
          window.pack();

          field.addFocusListener(new NoisyFocusListener("Field"));
          window.addFocusListener(new NoisyFocusListener("Window"));

          window.setVisible(true);
          field.requestFocus();
        }
      });
      frame.setVisible(true);
    }

    static class NoisyFocusListener implements FocusListener {
      private String name;
      public NoisyFocusListener(String name) {
        this.name = name;
      }
      public void focusGained(FocusEvent e) {
        System.out.println(name + (e.isTemporary() ? " got temporary focus." : " got focus."));
      }
      public void focusLost(FocusEvent e) {
        System.out.println(name + (e.isTemporary() ? " lost temporary focus." : " lost focus."));
      }
    }
  }
(Review ID: 48582)
======================================================================

This bug turns out to be a show stopper for a shipping SAP application.
They worked around it by shipping their application on 1.1.6.
They run in other problems now which are fixed in higher releases!
This bug is now a show stopper for a shipping, revenue generating 
commercial Java application (Hotel management).

Merlin beta is far out and unacceaptable

Regards

Stefan Schneider


stefan.schneider@eng 1999-11-12

This is also causing an accessibility problem for JavaHelp V1.1 popups in the ContentViewer. We cannot adequately test the code to verify a correct fix for setting focus to the popup.

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: merlin-beta FIXED IN: merlin-beta INTEGRATED IN: 1.3.0_02 1.3.1 merlin-beta VERIFIED IN: 1.3.0_02
14-06-2004

EVALUATION First, note that this is a different problem than the corresponding (solaris) problem that involves only heavyweight components. A fix for the heavyweight problem will not automatically fix this one, I don't think. The lightweight problem occurs on both platforms; the heavyweight one (for which there are other bug reports filed) occurs only on Solaris. I think that the problem here is the following code in Container.java's proxyRequestFocus method: if (dispatcher.setFocusRequest(c)) { Component window = this; while (!(window instanceof Window)) window = window.getParent(); if (((Window)window).isActive()) { peer.requestFocus(); } The problem here is that if the lightweight requesting focus is placed inside a Window that's not a Frame or Dialog, then dipatcher.setFocusRequest will return true (because the Window never actually should have focus -- instead, the Frame or Dialog that owns it should get the key events and dispatch them to the Window when appropriate). Then the first loop will find the containing Window, but it will never be active, since Windows are never active, only the Frames that own them are. So the requestFocus will never happen, which is okay, because Windows aren't supposed to get keyboard events directly. But what needs to then happen instead is that keyboard events that go to the owning Frame need to be passed to the lightweight in the owned Window -- for that, I think that the owning Frame's setFocusRequest needs to be called to set the "focus" field to the appropriate lightweight in the owned Window. Or some such. hania.gajewska@Eng 1999-02-09 We have been unable to track down the bug. We will have to revisit this for kestrel. david.mendenhall@eng 1999-04-05 06/24/1999 sandeep.konchady@eng: This bug is reproducible with JDK 1.2.2 under solaris 2.6. This does not have a lot of votes (count : 18) in bug parade. This could be fixed in kestrel, but does not seem important at least from customer/user perspective. Not true. It has 66 votes and is on the top 25. We will definitely target it for kestrel. david.mendenhall@eng 1999-07-30 CTE is developing a 1.2.2 patch for this bug, but the patch will not be put into an actual SDK release. As with all CTE patches, it will be available only to specific customers through the escalation process. The focus rewrite in merlin will address this bug in a more elegant and robust fashion. david.mendenhall@eng 2000-02-29 This bug is not fixed. The CTE patch which fixes this bug is available only on Windows, and is not generally available even on that platform. In addition, the patch is only a temporary fix. As I stated above, a complete fix for this bug will not be available until merlin. In the future, please contact a bug's responsible engineer before closing it. david.mendenhall@eng 2000-05-10
10-05-2000

SUGGESTED FIX Following are the files being changed: /win32/native/sun/windows/awt_Component.cpp /win32/native/sun/windows/awt_Window.h /win32/native/sun/windows/awt_Window.cpp /share/classes/java/awt/Container.java /share/classes/java/awt/Window.java ------- awt_Component.cpp ------- *** /tmp/dS8BKj_ Tue Jan 18 13:58:16 2000 --- awt_Component.cpp Tue Nov 30 16:20:46 1999 *************** *** 1071,1076 **** --- 1071,1079 ---- MsgRouting AwtComponent::WmSetFocus(HWND hWndLost) { + if (GetHWnd() == hWndLost) + return mrDoDefault; + SendFocusEvent(java_awt_event_FocusEvent_FOCUS_GAINED); return mrDoDefault; } *************** *** 1080,1085 **** --- 1083,1091 ---- HWND newTop = NULL; HWND oldTop = NULL; + if (GetHWnd() == hWndGotFocus) + return mrDoDefault; + // Determine new top-level window with component gaining the focus newTop = AwtComponent::GetTopLevelParentForWindow(hWndGotFocus); ------- awt_Window.h ------- *** /tmp/dQYTZv_ Tue Jan 18 14:00:16 2000 --- awt_Window.h Tue Jan 18 11:18:37 2000 *************** *** 30,36 **** /* java.awt.Window field ids */ static jfieldID warningStringID; ! AwtWindow(); virtual ~AwtWindow(); --- 30,37 ---- /* java.awt.Window field ids */ static jfieldID warningStringID; ! static jfieldID nativeActiveID; ! AwtWindow(); virtual ~AwtWindow(); *************** *** 80,85 **** --- 81,87 ---- /* * Windows message handler functions */ + virtual MsgRouting WmActivate(UINT nState, BOOL fMinimized); virtual MsgRouting WmCreate(); virtual MsgRouting WmClose(); virtual MsgRouting WmDestroy(); ------- awt_Window.cpp ------- *** /tmp/dz8Jy7_ Tue Jan 18 14:00:43 2000 --- awt_Window.cpp Tue Jan 18 11:22:27 2000 *************** *** 33,39 **** */ jfieldID AwtWindow::warningStringID; ! /************************************************************************ * AwtWindow class methods */ --- 33,39 ---- */ jfieldID AwtWindow::warningStringID; ! jfieldID AwtWindow::nativeActiveID; /************************************************************************ * AwtWindow class methods */ *************** *** 361,366 **** --- 361,385 ---- env->DeleteLocalRef(event); } + MsgRouting AwtWindow::WmActivate(UINT nState, BOOL fMinimized) + { + JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); + if (env->EnsureLocalCapacity(1) < 0) { + return mrConsume; + } + + jobject target = GetTarget(env); + + if (nState == WA_INACTIVE) { + env->SetBooleanField(target, AwtWindow::nativeActiveID, FALSE); + } + else { + env->SetBooleanField(target, AwtWindow::nativeActiveID, TRUE); + } + env->DeleteLocalRef(target); + return mrDoDefault; + } + MsgRouting AwtWindow::WmCreate() { return mrDoDefault; *************** *** 706,711 **** --- 725,734 ---- AwtWindow::warningStringID = env->GetFieldID(cls, "warningString", "Ljava/lang/String;"); + AwtWindow::nativeActiveID = + env->GetFieldID(cls, "nativeActive", "Z"); + + CATCH_BAD_ALLOC; } ------- Container.java ------- *** /tmp/dOXDJ4_ Tue Jan 18 13:54:44 2000 --- Container.java Tue Nov 30 16:15:01 1999 *************** *** 1245,1253 **** Component window = this; while (!(window instanceof Window)) window = window.getParent(); ! if (((Window)window).isActive()) { peer.requestFocus(); ! } Toolkit.getEventQueue().changeKeyEventFocus(this); } } --- 1245,1255 ---- Component window = this; while (!(window instanceof Window)) window = window.getParent(); ! if (((Window)window).isActive() || ! ! (window instanceof Frame || ! window instanceof Dialog) ) { peer.requestFocus(); ! } Toolkit.getEventQueue().changeKeyEventFocus(this); } } ------- Window.java ------- *** /tmp/d0x73iI Tue Jan 18 13:56:34 2000 --- Window.java Tue Jan 18 11:15:08 2000 *************** *** 62,67 **** --- 62,68 ---- * @see getWarningString() */ String warningString; + boolean nativeActive; static final int OPENED = 0x01; *************** *** 704,711 **** * assigned to them. */ public Component getFocusOwner() { ! if (active) ! return focusMgr.getFocusOwner(); else return null; } --- 705,713 ---- * assigned to them. */ public Component getFocusOwner() { ! if ( active || nativeActive) ! return focusMgr.getFocusOwner(); else return null; } ###@###.### 2000-01-19
19-01-2000