Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4094565
Votes 10
Synopsis Calling 'toFront()' on non-visible Window, Frame, and/or Dialogs is bad.
Category java:classes_awt
Reported Against 1.1 , 1.3 , 1.1.4 , 1.1.5 , 1.3.1 , cde1.2 , 1.1.8_003
Release Fixed 1.4(merlin-beta)
State 10-Fix Delivered, bug
Priority: 4-Low
Related Bugs 4036120 , 4190096 , 4401197 , 4133337
Submit Date 21-NOV-1997
Description




**** please CC: Saul Wold (  xxxxx@xxxxx  ) on any emails sent ****

If an instance of Window, Frame, or Dialog is currently non-visible, and
the 'toFront()' method is called, the window is typically shown, but 
the component doesn't think it's visible.  This causes strange things 
to happen, like calling 'setVisible(false)' on the component will not 
cause the window to hide.

The solaris source reveals that calling toFront() results in a call 
to 'pShow' in the Motif peer code, which always shows the X-Window.

IT GETS WORSE!
With respect to Dialogs, if the dialog is modal, calling "toFront()" 
will BLOCK inside the peer code!  ie., there is still code in the 
Solaris peer code that does the blocking for modal dialogs, but there 
is also code in java.awt.Dialog to handle the block by creating another 
thread to process the event queue.  So, if you call 'toFront()', the 
peer's blocking code goes off, but the new event queue thread never 
gets created.  If the call was made from the AWT event queue thread, 
then no more java AWT events get dispatched, which is REALLY BAD.

On windows NT, the problem of a hidden window showing itself does not 
exists, but calling "toFront()" on a hidden modal dialog does cause
problems.  The parent frame of the dialog will 
no longer accept mouse input after the 'toFront' 
method of the non-visible dialog has been called.
(Review ID: 20570)
======================================================================

  xxxxx@xxxxx   1998-04-09

There is a potential GUI lockup when using AWT modal dialogs on Solaris.
If you call toFront() on a modal dialog which is already showing
the GUI locks up.

This bug is reproducible on Solaris/Motif with JDK 1.1.5 & JDK 1.2 Beta3

Suppose an application has a button which shows a modal dialog
In theory once the button is pressed, the modal dialog is immediately
in effect and the user cannot press it again until the modal dialog
is dismissed.

However it is possible that the user can press this button twice before
the modal dialog is in fact shown.

This can happen if the application was "busy" enough that the user
managed to press the button again before the modality is in effect.
This can happen in real applications being run on busy or slow machines.

The other way this bug can happen is if the application were to attempting
to detect and prevent this from happening, and decide instead to just
call toFront().

In fact both of these reduce to the same internal problem since
the Dialog's show method just calls toFront() if the Dialog is already
visible.

An argument could be made that this is "not a bug" and the application
should always check whether the dialog is visible before showing it
again. But our API docs certainly do not prohibit calling toFront() on a
modal dialog.

So we don't document not to call toFront, or show on an already visible
modal dialog, and if it happens the application is completely locked.
Also even if we did document it, this puts the onus on the application
programmer to guard against this problem in all places s/he uses a modal
dialog.

Also this bug does not occur under NT, so an application programmer
doing development and testing will see a platform specific bug.

[[Actually there is ANOTHER Dialog bug I came across whilst looking
at this one, also related to the toFront() method.
The toFront() method is supposed to raise a window if already on
screen, and to create and show it, if not already on screen.
If you call toFront() on an unshown dialog, modal or otherwise it
does not get shown.]]

To reproduce the GUI lockup problem
------------------------------------

Compile and run this program
// ModalTestFrame.java
import java.awt.*;
import java.awt.event.*;

public class ModalTestFrame extends Frame implements ActionListener {

  Button longButton;
  Button showButton;
  Dialog dialog;
  Button dismissButton;

  public static void main(String[] args) {
      ModalTestFrame f = new ModalTestFrame();
      f.setBounds(200,200,200,100);
      f.setVisible(true);
  }

  public ModalTestFrame() {
    super("Modal Test Frame");

    longButton = new Button("Long event");
    longButton.addActionListener(this);
    add("North", longButton);

    showButton = new Button("Show Dialog");
    showButton.addActionListener(this);
    add("South", showButton);

    dialog = new Dialog(this, "Modal Dialog 1", true);
    dismissButton = new Button("Dismiss 1");
    dismissButton.addActionListener(this);
    dialog.add("Center", dismissButton);
    dialog.setBounds(200,300,100,100);
 }

 public void actionPerformed(ActionEvent e) {
    if (e.getSource() == longButton) {
        System.out.println("Sleeping for 2 secs");
        try {
              Thread.sleep(2000);
        } catch (InterruptedException ex) {
        }
    }
    if (e.getSource() == showButton) {
        System.out.println("Show");
        if (dialog.isVisible()) {
           System.out.println("Already visible, bringing toFront");
           dialog.toFront();
        }
        else
          dialog.setVisible(true);
        Toolkit.getDefaultToolkit().sync();
    }
    if (e.getSource() == dismissButton) {
        System.out.println("Dismiss");
        dialog.setVisible(false);
    }
 }

}

Using the test program press the button labelled "Long event". Next
immediately press the "Show Dialog" button twice.

You will see the following text printed out

Sleeping for 2 secs
Show
Show
Already visible, bringing toFront
The 2nd "Show" message indicates that the application had queued
a 2nd button action before the modal dialog from the 1st took effect.
The test program could have called setVisible(true) again but in this
case actually calls toFront().
Both of these cause the lockup and neither should!

The following extract from a thread dump of the test program
(below) shows what happens.

Full thread dump:
    "AWT-Modal" (TID:0xee312348, sys_thread_t:0x24e9c8, state:CW) prio=5
        at java.lang.Object.wait(Native Method)
        at sun.awt.motif.MDialogPeer.pShow(Native Method)
        at sun.awt.motif.ModalThread.run(MDialogPeer.java:212)
    "AWT-Dispatch-Proxy" (TID:0xee312318, sys_thread_t:0x24c418, state:CW) pri
o=5
        at java.lang.Object.wait(Native Method)
        at sun.awt.motif.MDialogPeer.pShow(Native Method)
        at sun.awt.motif.MDialogPeer.toFront(MDialogPeer.java:181)
        at java.awt.Window.toFront(Window.java:231)
        at ModalTestFrame.actionPerformed(ModalTestFrame.java:47)
        at java.awt.Button.processActionEvent(Button.java:248)
        at java.awt.Button.processEvent(Button.java:221)
        at java.awt.Component.dispatchEventImpl(Component.java:2041)
        at java.awt.Component.dispatchEvent(Component.java:1951)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:167)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:45)

Monitor Cache Dump:
      xxxxx@xxxxx  /EE39EE80: owner "AWT-Modal" (0x24e9c8,
1 entry)
        Waiting to be notified:
            "AWT-EventQueue-0" (0x1bb150)

Basically we have two threads, each executing the pShow() native method for
the same dialog peer.

The first thread is waiting on notification from the event dispatcher thread,
via the awt_lock  customer , that an event is ready and has been dispatched.
But the other thread waiting *is* the event dispatcher thread, and its
waiting on a condition too: not dispatching events.
It gets woken up whenever there's input, but immediately waits again
because it believes there's some other modal dialog active that this
one needs to wait for.

Here's some more detail on how the modal show is supposed to work:

The "AWT-Dispatch-Proxy" event dispatcher thread is created when attempting to
show a modal dialog from an event processing thread (in this case
the main AWT dispatcher thread, "AWT-EventQueue-0").
This is because the thread doing the show will block but we must
continue dispatching events. the proxy does this while the modal is showing.
If we were to block the event dispatcher, without starting the proxy thread,
then the GUI would freeze, because events would simply queue up and never
be delivered, including the ones to the dialog which would dismiss it.

Next the "AWT-Modal" thread is created by the dialog's peer  customer  to
do the actual show. The original thread ("AWT-EventQueue-0" in the case of
the first show) waits on a notification from this thread.
This indirection via the "AWT-Modal" thread is needed to have a
minimal and  customer  call stack in the showing thread.
That the "AWT-EventQueue-0" (main AWT event queue) holds the AWT-Modal lock
can be confirmed looking at the Monitor Dump Cache.

The AWT-Modal thread calls the peer's pShow() native method.
pShow() then calls a function which will wait for the next event
to be delivered. To do this the called function obtains acquires the toolkit's
awt_lock, but then releases it and waits for notification on that lock
which is interpreted to mean that an event is ready for processing.

That's an overview of what happens.

However in the second show when we do a toFront() from the proxy dispatcher
thread, there is no new dispatcher set up to take over.
Possibly because it was supposed that toFront really did nothing more
than a window raise and return ..
But  customer  that it calls the same show code we could expect this lock up.
However there is one more wrinkle which contributes to this bug.
We don't even get to the point where the thread blocks waiting for
the modal to be dismissed.
The code actually thinks another modal has been popped up above this
one and is waiting for it.

The modal dialog is assigned a number which is probably used to
support nested modal dialogs.
This number is intended to be per dialog, but ends up being per thread.
The value gets set to 2 because there are 2 threads trying to show the dialog.

One thread is now blocked waiting for the active modal to be number 1.
The seconds thread numbered 2 is blocked waiting for events, but not getting
them because the other thread is the dispatcher.

Workaround:
Never call toFront() on a Dialog, use show() or setVisible(true);
Always check if a Dialog is visible before showing it, and don't
make the call if its not needed.

Work Around




Don't call 'toFront' on non-visible windows.  This really means either
overloading the "toFront" method of Window/Frame/Dialog and only 
calling super.toFront if 'this' is visible, or enclosing any call 
to toFront with an 'if (window.isVisible())' conditional.
======================================================================

  xxxxx@xxxxx   1998-04-09

Never call toFront() on a Dialog, use show() or setVisible(true);
Always check if a Dialog is visible before showing it, and don't
make the call if its not needed.
Evaluation
Fixed during merlin focus rewrite. toFront() and toBack() now NOP if the Window
is not visible.
  xxxxx@xxxxx   2000-10-02
Comments
  
  Include a link with my name & email   

Submitted On 16-MAY-1998
ignacio
I allmost Emailed Mulder and Scully after this 
bug. 
  I suggest to use setVisible(true) instead of 
toFront.


Submitted On 03-SEP-1999
41Daisy
Similar results with requestFocus. These seem to
have been introduced by releases subsequent to 
1.1.6 which did not have these problems. No
workaround discovered apart from manual click on
taskbar. (environment 1.2.2 & win98)  


Submitted On 08-MAR-2001
ksfrahman
i do not know how to keep a window always visible always
without overlaping(toFront() and show() not working)
can anybody help me.

              ksfrahman@usa.net



PLEASE NOTE: JDK6 is formerly known as Project Mustang