JDK-4088877 : Multiple modal dialogs can be created before block takes effect
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.1.3,1.2.2
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_2.5.1,windows_nt
  • CPU: x86,sparc
  • Submitted: 1997-10-27
  • Updated: 2001-10-19
  • Resolved: 2000-05-10
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 Other
1.2.2_005 005Fixed 1.3.0_02Fixed 1.3.1Fixed 1.4.0Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Description

Name: joT67522			Date: 10/27/97


/*
 * java.awt.Dialog blocking bug
 * Jason Mathews
 * Fri, Oct 24, 06:11:17 PM
 *
 * Problem: Modal dialogs do not block fast enough allowing for multiple
 * modal dialog instances to be created before the block is enabled.
 *
 * Clicking on the "Create Modal Dialog..." button on applet/frame several
 * times in rapid succession brings up multiple dialog windows. It appears
 * that there's a race condition of whether the first modal dialog
 * invokes the modal block or the subsequent Button events are processed by
 * the applet's event handler. The create dialog button event is handled
 * before the first modal dialog instance invokes the modal block, hence
 * multiple dialogs are created when you only want one.
 *
 * Works as expected under JDK 1.0.2 where blocking
 * is immediate. However, the modal block in
 * JDK 1.1.3 is slow to respond to the lock.
 *
 * Same behavior on SGI/IRIX 5.3 and DEC Alpha OSF.
 */

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

class TestDialog extends Dialog {

  public TestDialog(Frame parent, String title) {
    super(parent, title, true);
    System.err.println("create: " + title);
    setLayout(new BorderLayout(15,15));
    // do something that takes a little time
    for (int i=1; i < 100000; i++)
      new Integer(i);
    add("Center", new Label("This a test", Label.CENTER));
    add("South", new Button("Ok"));
    resize(200,80);
    System.err.println("show: " + title);
    show();
  }

  public boolean action (Event e, Object arg) {
    if (e.target instanceof Button) {
      hide();
      dispose();
      return true;
    }
    return false;
  }

}

------- BugDialog.java ----------


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

public class BugDialog extends Applet {

  int count = 1;
  boolean workaround = false;

  public BugDialog() {
    add(new Button("Create Modal Dialog..."));
    add(new Checkbox("Enable workaround"));
    resize(100,100);
  }

  public boolean action(Event e, Object o) {
    if (e.target instanceof Button)  {
      Container parent = getParent();
      while (parent != null && ! (parent instanceof Frame) )
	parent = parent.getParent();
      if (workaround) disable();
      new TestDialog((Frame)parent, "Modal Dialog " + count++);
      if (workaround) enable();
    } else if (e.target instanceof Checkbox) {
      workaround = ((Checkbox)e.target).getState();
      System.err.println("workaround " + workaround);
    } else {
      return false;
    }
      return true;

  }
  
  public static void main (String args[])
  {
    Frame f = new Frame("BugDialog");
    BugDialog d = new BugDialog();
    d.init();
    d.start();
    f.add("Center", d);
    f.pack();
    f.show();
  }

}
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.2.2_005 ladybird merlin-rc1 FIXED IN: 1.2.2_005 ladybird merlin-beta2 INTEGRATED IN: 1.2.2_005 1.3.0_02 1.3.1 ladybird merlin-beta2 VERIFIED IN: 1.2.2_005 1.3.0_02 1.3.1_01a
14-06-2004

WORK AROUND Name: joT67522 Date: 10/27/97 disable() applet before creating dialog and enable() after it is created. ======================================================================
11-06-2004

PUBLIC COMMENTS Problem is that modal dispatcher thread is fired up _before_ dialog actually appears. It is during this interval (can be several seconds) that events are being dispatched on the frame window by the modal dispatcher thread. We now listen to the EventQueue for the dialog to get a WINDOW_ACTIVATED event. When we see this we know it's safe to fire up the dispatcher thread since the dialog is visible and the frame is deactivated by the modality.
10-06-2004

SUGGESTED FIX the problem is that the action we take to process one event might change the future event sequence. so ideally we should do eventloop in strict order: while (1) { get one event, process this event } the current 2 threads implementation might get in more than one event before processing it. for 1.2.2 patch i made the following change to workaround the above problem: in dialog's modal show(), filter out input event directed to other component when pumping events. ------- Dialog.java ------- *** /tmp/d0HfllV Tue Feb 15 11:55:50 2000 --- Dialog.java Tue Feb 15 11:53:32 2000 *************** *** 369,379 **** if (Toolkit.getEventQueue().isDispatchThread()) { EventDispatchThread dispatchThread = (EventDispatchThread) Thread.currentThread(); ! dispatchThread.pumpEvents(new Conditional() { public boolean evaluate() { return keepBlocking; } ! }); return; } --- 369,389 ---- if (Toolkit.getEventQueue().isDispatchThread()) { EventDispatchThread dispatchThread = (EventDispatchThread) Thread.currentThread(); ! /* ! * pump events, filter out input events for ! * component not belong to our modal dialog. ! * ! * we already disabled other components in native code ! * but because the event is posted from a different ! * thread so it's possible that there are some events ! * for other component already posted in the queue ! * before we decide do modal show. ! */ ! dispatchThread.pumpEventsForComponent(new Conditional() { public boolean evaluate() { return keepBlocking; } ! }, (Component)this); return; } EventDispatchThread.java: *** /tmp/geta12363 Mon Mar 20 14:59:33 2000 --- /tmp/getb12363 Mon Mar 20 14:59:33 2000 *************** *** 17,24 **** import java.lang.reflect.Method; import java.security.AccessController; import sun.security.action.GetPropertyAction; - /** * EventDispatchThread is a package-private AWT class which takes * events off the EventQueue and dispatches them to the appropriate --- 17,24 ---- import java.lang.reflect.Method; import java.security.AccessController; import sun.security.action.GetPropertyAction; + import java.awt.event.InputEvent; /** * EventDispatchThread is a package-private AWT class which takes * events off the EventQueue and dispatches them to the appropriate *************** *** 88,95 **** } void pumpEvents(Conditional cond) { while (doDispatch && cond.evaluate()) { ! if (isInterrupted() || !pumpOneEvent()) { doDispatch = false; } } --- 88,99 ---- } void pumpEvents(Conditional cond) { + pumpEventsForComponent(cond, null); + } + + void pumpEventsForComponent(Conditional cond, Component modalComponent) { while (doDispatch && cond.evaluate()) { ! if (isInterrupted() || !pumpOneEventForComponent(modalComponent)) { doDispatch = false; } } *************** *** 96,103 **** --- 100,123 ---- } boolean pumpOneEvent() { + return pumpOneEventForComponent(null); + } + + boolean pumpOneEventForComponent(Component modalComponent) { try { AWTEvent event = theQueue.getNextEvent(); + if (modalComponent != null) { + while (event instanceof InputEvent) { + Component c = (Component)event.getSource(); + // check if c's modalComponent's child + while (c != modalComponent && c != null) + c = c.getParent(); + if (c != modalComponent) + event = theQueue.getNextEvent(); + else + break; + } + } theQueue.dispatchEvent(event); return true; } catch (ThreadDeath death) { tao.ma@Eng 2000-03-20
20-03-2000

EVALUATION Problem is that modal dispatcher thread is fired up _before_ dialog actually appears. It is during this interval (can be several seconds) that events are being dispatched on the frame window by the modal dispatcher thread. This will be fixed in 1.2 by event queue stacking and moving modal dialog code into java. ---------------- i tested the test case, clicking very fast on the button, sometime you will get two modal dialog at the same time. (both 1.2.2 and 1.3) i think the problem is that at the time the button's action handler is calling Dialog.show(), native message thread has already post another mouse click to that button. changing the code in Dialog.show() to filter out InputEvent directed to component not belonging to the current modal dialog seems to work. tao.ma@Eng 2000-02-14 Comitting to Merlin richard.ray@eng 2001-02-20 i have putback the fix in awt 1.4 ws tao.ma@Eng 2001-08-02
14-02-2000