JDK-4484572 : Modal JOptionPane.showMessageDialog locks if called during Drag-N-Drop
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.3.1
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_2.6
  • CPU: sparc
  • Submitted: 2001-07-26
  • Updated: 2002-06-17
  • Resolved: 2002-04-25
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
1.4.1 hopperFixed
Related Reports
Relates :  
Relates :  
Description
Starting a modal dialog using JOptionPane.showMessageDialog()
deadlocks, with a grabbed Xserver, if it is started while a drag-n-drop
operation is in progress (it is called from invokeLater).


As part of the DragGestureListener implementation, a dragGestureRecognized 
method is called when the drag starts.

This does a Thread.sleep(2000) (for example), to ensure the drag is underway.

Then it calls JOptionPane.showMessageDialog(null, new String("Click Me")

This is done with invokeLater:

SwingUtilities.invokeLater(new Runnable()
 {
        public void run() {
        JOptionPane.showMessageDialog(null, new String("Click Me"));

to be "safe": the invokeLater is run in the AWT Event Queue, and the
Dialog.show starts a new Event "pump".  

However, if the mouse button was still held (drag still in progress, Xserver 
still grabbed), this event pump to deal with the "show" operation will
never complete, and the app locks up.

As the X server was grabbed by the app as part of the drag operation, 
the mouse and keyboard are unusable by other X clients.

Comparing a non-modal dialog: the contents of a frame cannot be drawn while
the drag is in progress.  However, this is a delay rather than deadlock, as the
creation of a Frame is not a blocking call.

The same (Modal) code is fine on Windows' JDK.

Testing on Java 1.4 Beta, similar behaviour is observed but
the dialog box does draw itself, and repaints itself when necessary.
It still does not respond to mouse clicks, and the mouse still appears 
"grabbed": no window manager 'move' operations are possible, for example.

Believe suspect this new bug is seen after implementing the solution for 4352221

To Reproduce:
------------
Cusomter testcase attached: SunLock.java

Any Solaris Java 2 JDK will show problems. Compile with:
	javac SunLock.java
Run with:
	java SunLock

Start a drag operation in the window presented, and wait (keep mouse button
depressed).   A modal dialog will attempt to display.


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

Further details:

Using a reference version to get a monitor cache dump
1.2.2_007 reference shows:

Monitor Cache Dump:
...
    java.lang.Class@FB8AB460/FB91DCF8: owner "AWT-Motif" (0x363d98) 1 entry
        Waiting to enter:
            "AWT-EventQueue-0" (0x300420)
...

Where:
    "AWT-Motif" (TID:0xfb8bc2b0, sys_thread_t:0x363d98, state:CW) prio=5
        at sun.awt.motif.MToolkit.run(Native Method)
        at java.lang.Thread.run(Thread.java, Compiled Code)

And:
    "AWT-EventQueue-0" (TID:0xfb8bc890, sys_thread_t:0x300420, state:MW) prio=6
        at sun.awt.motif.MComponentPeer.nativeHandleEvent(Native Method)
        at sun.awt.motif.MComponentPeer.handleEvent(MComponentPeer.java, Compiled Code)
        at java.awt.Component.dispatchEventImpl(Component.java, Compiled Code)
        at java.awt.Container.dispatchEventImpl(Container.java, Compiled Code)
        at java.awt.Window.dispatchEventImpl(Window.java, Compiled Code)
        at java.awt.Component.dispatchEvent(Component.java, Compiled Code)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java, Compiled Code)
        at java.awt.EventDispatchThread.pumpOneEventForComponent(EventDispatchThread.java, Compiled
 Code)
        at java.awt.EventDispatchThread.pumpEventsForComponent(EventDispatchThread.java, Compiled C
ode)
        at java.awt.Dialog.show(Dialog.java, Compiled Code)



Similarly, 1.3.1 Production shows:

"AWT-Motif" prio=6 tid=0x1ec4d0 nid=0xe runnable [0xf4601000..0xf46019e0]
        at sun.awt.motif.MToolkit.run(Native Method)
        at java.lang.Thread.run(Thread.java:484)


and:

"AWT-EventQueue-0" prio=6 tid=0x197ba0 nid=0xc waiting for monitor entry [0xf4800000..0xf48019e0]
        at sun.awt.motif.MGlobalCursorManager.findHeavyweightUnderCursor(Native Method)
        at sun.awt.motif.MGlobalCursorManager.findHeavyweightUnderCursor(MGlobalCursorManager.java:
62)
        at sun.awt.GlobalCursorManager._updateCursor(GlobalCursorManager.java:182)
        at sun.awt.GlobalCursorManager.updateCursorImmediately(GlobalCursorManager.java:91)
        at java.awt.Container.validate(Container.java:737)
        at java.awt.Window.dispatchEventImpl(Window.java:897)
        at java.awt.Component.dispatchEvent(Component.java:2497)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:339)
        at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:131)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:98)
        at java.awt.Dialog.show(Dialog.java:380)


We believe findHeavyweightUnderCursor wants to acquire the awt_lock.
Noting the mutex acquired at a native Solaris level, it is the AWT-Motif thread 
which holds the thing the Event queue wants.

However, the AWT-Motif thread is, at a Solaris level, in a poll which does 
not return.


Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: hopper FIXED IN: hopper INTEGRATED IN: hopper VERIFIED IN: hopper-beta
17-09-2004

WORK AROUND Workaround: Check for drag in progress before requesting a modal dialog. Actively cancel the drag before requesting a modal dialog.
17-09-2004

PUBLIC COMMENTS Starting a modal dialog using JOptionPane.showMessageDialog() deadlocks, with a grabbed Xserver, if it is started while a drag-n-drop operation is in progress (it is called from invokeLater).
17-09-2004

SUGGESTED FIX Name: dsR10078 Date: 04/01/2002 With the fix for 4111035 and 4124096 the dialog modality is implemented by keeping a list of modal widgets and filtering out all events that are outside of the modal widget hierarchy. With this fix X grabs are no longer needed and can be removed. --- awt_TopLevel.c Mon Apr 1 12:46:40 2002 *************** *** 2738,2744 **** --- 2738,2746 ---- wdata->callbacksAdded = True; } #endif /* !NOMODALFIX */ + + #ifdef NOMODALFIX /* * Set modality on the Shell, not the BB. The BB expects that * its parent is an xmDialogShell, which as the result of * coalescing is now a transientShell... This has resulted in *************** *** 2750,2755 **** --- 2752,2758 ---- XtVaSetValues(wdata->winData.shell, XmNmwmInputMode, MWM_INPUT_FULL_APPLICATION_MODAL, NULL); + #endif /* NOMODALFIX */ XtManageChild(wdata->winData.comp.widget); } else { /* not modal */ --- awt_FileDialog.c Mon Apr 1 12:45:49 2002 *************** *** 347,354 **** --- 347,357 ---- argc++; XtSetArg(args[argc], XmNvisual, adata->awt_visInfo.visual); argc++; + + #ifdef NOMODALFIX XtSetArg(args[argc], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); argc++; + #endif /* NOMODALFIX */ XtSetArg (args[argc], XmNscreen, ScreenOfDisplay(awt_display, adata->awt_visInfo.screen)); argc++; ###@###.### 2002-04-01 ====================================================================== Name: dsR10078 Date: 04/04/2002 Investigation shows that the fix for 4111035 and 4124096 doesn't fully emulate the Xt passive grab. Events are still dispatched to menus and scrollbars that are outside of the modal subtree. An attempt to fully emulate the Xt passive grab required to duplicate a large block of code from Xt. Such an extent changes that affect not only DnD, but modal dialogs and popup menus as well is considered to risky at this point. An alternative fix is to cancel the drag operation whenever a modal widget pops up. To do this we override the 'initialize' routine in the shellWidgetClass to install an XtNpopupCallback on all ShellWidget instances. The XtNpopupCallback is to register a timer procedure that cancels the current drag operation. Also the timer procedure should putback a dummy event, so that Motif DnD can cleanly exit from the drag-and-drop internal event loop. This fix also resolves a similar deadlock when a popup menu is displayed during the drag operation. --- awt_XmDnD.c Thu Apr 4 13:57:00 2002 *************** *** 157,162 **** --- 157,257 ---- } } + static void + cancel_drag(XtPointer client_data, XtIntervalId* id) { + Time time = awt_util_getCurrentServerTime(); + Widget dc = XmGetDragContext(awt_root_shell, time); + + if (dc != NULL) { + Boolean sourceIsExternal = True; + XtVaGetValues(dc, XmNsourceIsExternal, &sourceIsExternal, NULL); + if (!sourceIsExternal) { + XEvent xevent; + XmDragCancel(dc); + + /* + * When running the internal drag-and-drop event loop + * (see DragC.c:InitiatorMainLoop) Motif DnD uses XtAppNextEvent, + * that processes all timer callbacks and then returns the next X + * event from the queue. Motif DnD doesn't check if the drag + * operation is cancelled after XtAppNextEvent returns and processes + * the returned event. When the drag operation is cancelled the + * XmDragContext widget is destroyed and Motif will crash if the new + * event is dispatched to the destroyed XmDragContext. + * We cancel the drag operation in the timer callback, so we putback + * a dummy X event. This event will be returned from XtAppNextEvent + * and Motif DnD will safely exit from the internal event loop. + */ + xevent.type = LASTEvent; + xevent.xany.send_event = True; + xevent.xany.display = awt_display; + xevent.xany.window = XtWindow(awt_root_shell); + XPutBackEvent(awt_display, &xevent); + } + } + } + + #define DONT_CARE -1 + + static void + awt_popupCallback(Widget shell, XtPointer closure, XtPointer call_data) { + XtGrabKind grab_kind = XtGrabNone; + + if (call_data != NULL) { + grab_kind = *((XtGrabKind*)call_data); + } + + if (XmIsVendorShell(shell)) { + int input_mode; + XtVaGetValues(shell, XmNmwmInputMode, &input_mode, NULL); + switch (input_mode) { + case DONT_CARE: + case MWM_INPUT_MODELESS: + grab_kind = XtGrabNonexclusive; break; + case MWM_INPUT_PRIMARY_APPLICATION_MODAL: + case MWM_INPUT_SYSTEM_MODAL: + case MWM_INPUT_FULL_APPLICATION_MODAL: + grab_kind = XtGrabExclusive; break; + } + } + + if (grab_kind == XtGrabExclusive) { + /* + * We should cancel the drag on the toolkit thread. Otherwise, it can be + * called while the toolkit thread is waiting inside some drag callback. + * In this case Motif will crash when the drag callback returns. + */ + XtAppAddTimeOut(awt_appContext, 0L, cancel_drag, NULL); + } + } + + static XtInitProc xt_shell_initialize = NULL; + + static void + awt_ShellInitialize(Widget req, Widget new, ArgList args, Cardinal *num_args) { + XtAddCallback(new, XtNpopupCallback, awt_popupCallback, NULL); + (*xt_shell_initialize)(req, new, args, num_args); + } + + /* + * Fix for 4484572. + * Modify the 'initialize' routine for all ShellWidget instances, so that it + * will install an XtNpopupCallback that cancels the current drag operation. + */ + static void + awt_set_ShellInitialize() { + static Boolean inited = False; + + DASSERT(!inited); + if (inited) { + return; + } + + xt_shell_initialize = shellWidgetClass->core_class.initialize; + shellWidgetClass->core_class.initialize = (XtInitProc)awt_ShellInitialize; + inited = True; + } + /** * global function to initialize this client as a Dynamic-only app. * *************** *** 191,196 **** --- 286,293 ---- */ awt_motif_enableSingleDragInitiator(awt_root_shell); + awt_set_ShellInitialize(); + /* * load the Cursor stuff */ ###@###.### 2002-04-04 ======================================================================
04-04-2002

EVALUATION Name: dsR10078 Date: 04/01/2002 Motif DnD uses X and Xt grabs to route all mouse and keyboard events to the drag initiator. The current implementation of modal dialogs on X11 also involves grabs. If a modal dialog is displayed while a drag operation is in progress, these grabs will conflict with DnD grabs and cause lockup. ###@###.### 2002-04-01 ======================================================================
01-04-2002