Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4138263

Regression in lightweight dispatcher: no longer delivers events synchronously

XMLWordPrintable

    • x86, sparc
    • solaris_2.5.1, windows_nt

      It is not possible to call
      requestFocus()
      on two different components in response to the same event without completely
      screwing up AWT's notion of the focused component. Unfortunately, EWT needs
      to be able to do this in a few different places (eg. in a editable Grid,
      clicking on a cell first calls requestFocus() on the Grid, then on the
      cell editor). This also currently effects lightweight windows due to some
      focus management code which gets called when activating a window.

      (EWT is a lightweight components graphics library)

      More details:

      Here's our understanding of the JDK 1.1.6 focus problems:

      Apparently JavaSoft has decided to change focus event delivery for
      lightweight components to be asynchronous (focus events are now queued
      instead of dispatched synchronously).

       - The focused component is redundantly stored in both the Window and the
         LightweightDispatcher (one of these per heavy weight component).

       - When a lightweight component requests the focus, this request is
         propagated to the nearest LightweightDispatcher above the lightweight
         component via Container.proxyRequestFocus().

       - This results in a call to LightweightDispatcher.setFocusRequest() for
         the requesting lightweight component.

       - In setFocusRequest(), the Window's focus owner is retrieved via
         Window.getFocusOwner(). (This just returns the Window's stored focus
         owner.)

       - If the window's focus owner matches the lightweight dispatcher's
         focus owner, the lightweight dispatcher queues focus lost/gained events
         for the old/new focus components and sets its focus owner to the new
         focus component. The Window is not updated immediately - it will update
         its focus owner when it receives the focus gained event for the new
         focus component (this now happens asynchronously).

      In most cases, this works out ok. However, since the lightweight
      dispatcher's focus component is updated synchronously and the Window's
      focus component is updated asynchronously, it is easy for these two
      values to become out of sync. In this case, the Lightweight
      dispatcher refuses to change the focus, as it seems that a
      prerequestite for a focus change to take place is that the
      LightweightDispatcher's focus component must be equal to the Window's
      focus component. We get into this state when the focus is requested
      on two different components while processing a single event.

      This problem is easily reproduced with an editable Grid. On a mouse
      press, two things happen:

        - The Grid requests the focus to itself,

      and then, when startCellEdit() is called

        - The Grid requests the focus to move the the cell editor

      Both of these focus changes occur in response to the same mouse
      pressed event.

      After the first call to request focus (on the Grid), AWT is in the
      following state:

       - LightweightDispatcher's focus == Grid
       - Window's focus == the old focus owner - whatever used to have the focus
       - FOCUS_LOST/FOCUS_GAINED events are posted at the front of the EventQueue

      Now, when we call requestFocus() on the editor component, the
      LightweightDispatcher checks to see whether its focus component
      matches the Window's focus component. Since the event dispatcher has
      not had a chance to deliver the focus change events to the Window (how
      could it? we are doing all of this processing in the event dispatcher
      thread in response to a single mouse event.), this test fails and the
      focus is not updated. (Actually, in this case the
      LightweightDispatcher quietly updates its own focus owner to the
      requesting component, but no focus events are generated and the Window
      never finds out about the change.)

      I haven't been able to come up with any generic work around for this
      problem. We may be able to work around the problem on a case by case
      basis by eliminating cases where requestFocus() is called on two
      different components in response to a single event. For example, we
      can update the Grid such that it does not immediately call
      requestFocus on its editor component, but instead defers this until it
      receives a FOCUS_GAINED event. This approach only works if we know
      which component is supposed to have the focus and we are sure that a
      focus gained event is pending. We can probably apply the same work
      around to other cases, but I think it is going to be very hard to get
      everything right. Basically, this means looking at *every* call to
      requestFocus() in both EWT code and client code and deciding whether
      it may be called in a thread for which requestFocus() has already been
      called on another component.

      As far as a fix for JavaSoft... I don't think there is a trivial
      solution. Basically they need to make sure that their
      LightweightDispatcher and Window stay in sync, which means changing
      the way their focus events are dispatched. See also 4131761.

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

      Test case is attached. It can also be found in
      ~mrm/Oracle/bugs/jdk/4138263

      marianne.mueller@Eng 1998-06-09

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

            rkhansunw Robi Khan (Inactive)
            mmuellersunw Marianne Mueller (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: