Opened 14 years ago

Closed 14 years ago

#45 closed defect (fixed)

Drag & Drop of text causes a ClassCastException

Reported by: dmik Owned by:
Priority: major Milestone: Beta 2
Component: general Version:
Severity: Keywords:
Cc:

Description

The following happens if one tries to drag & drop a block of selected text in the Notepad.jar demo application:

java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
        at javax.swing.TransferHandler$DropHandler.initPropertiesIfNecessary(TransferHandler.java:1345)
        at javax.swing.TransferHandler$DropHandler.dragEnter(TransferHandler.java:1432)
        at java.awt.dnd.DropTarget.dragEnter(DropTarget.java:353)
        at javax.swing.TransferHandler$SwingDropTarget.dragEnter(TransferHandler.java:1174)
        at sun.awt.dnd.SunDropTargetContextPeer.processEnterMessage(SunDropTargetContextPeer.java:324)
        at sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher.dispatchEnterEvent(SunDropTargetContextPeer.java:789)
        at sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher.dispatchEvent(SunDropTargetContextPeer.java:757)
        at sun.awt.dnd.SunDropTargetEvent.dispatch(SunDropTargetEvent.java:48)
        at java.awt.Component.dispatchEventImpl(Component.java:4324)
        at java.awt.Container.dispatchEventImpl(Container.java:2163)
        at java.awt.Component.dispatchEvent(Component.java:4295)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4461)
        at java.awt.LightweightDispatcher.trackMouseEnterExit(Container.java:4250)
        at java.awt.LightweightDispatcher.processDropTargetEvent(Container.java:4188)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4050)
        at java.awt.Container.dispatchEventImpl(Container.java:2149)
        at java.awt.Window.dispatchEventImpl(Window.java:2478)
        at java.awt.Component.dispatchEvent(Component.java:4295)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:604)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:138)
Exception in thread "Thread-1" java.lang.UnsatisfiedLinkError: sun.awt.windows.WToolkit.shutdown()V
        at sun.awt.windows.WToolkit.shutdown(Native Method)
        at sun.awt.windows.WToolkit.access$200(WToolkit.java:64)
        at sun.awt.windows.WToolkit$3.run(WToolkit.java:274)
        at java.lang.Thread.run(Thread.java:636)

Change History (10)

comment:1 by dmik, 14 years ago

The same operation in InnoTek Java 1.4.2 works well. I will try to look at it tomorrow before releasing Beta 2, just in case if it's easy to fix.

comment:2 by dmik, 14 years ago

The iTrain application (see #43) seems to show a similar behavior. Some Java exceptions when dragging and the GUI interface stuck in the "dragging" state.

comment:3 by dmik, 14 years ago

r237 fixes DnD in iTrain (i.e. one can drag a locomotive to the throttle window). Quite a strange vendor bug -- should have affected the Windows version too; probably nobody uses OpenJDK for Windows in practice (due to the easy availability of the Sun JDK).

DnD also started to work in Notepad but it sometimes only once: looks like it sticks forever in the DoDragDrop() call which never ends so you cannot start a second drag operation. Probably related to the mouse button tracking code. One may actually see a similar problem if he tries to drag a scrollbar handle in a standard Win32Os2 dialog, like the "About Odin" dialog available in any Odin application through the system menu of the window. I will look at it too.

comment:4 by dmik, 14 years ago

The problem with DnD in Notepad is that the order of messages in the multiply nested message loops used during DnD gets broken somehow so that the outermost loop does never return to DoDragDrop() and therefore doesn't let it return in turn and prevents starting a new drag operation.

It seems that the reason for that is the fact that Odin doesn't provide a correct implementation of GetQueueStatus(). This API should obsolete the messages already in the queue and return the respective bits in the low word only if there are new messages since the last call. However, in Odin it always returns the overall (old) information in both words and doesn't seem to obsolete the old messages.

As a result, a block of code like this:

    WaitMessage();
    GetQueueStatus(...);

spins forever on OS/2 occupying all the CPU which doesn't let other threads to kick in to perform an action and post a message the block is waiting for...

I will think on how to solve that.

comment:5 by dmik, 14 years ago

That is, WaitMessage() on Windows doesn't return if there are messages in the queue but they were obsoleted by GetQueueStatus() which lets other threads run. On OS/2, WaitMessage() always returns immediately if there is anything in the queue, regardless of whether it's old or new.

comment:6 by dmik, 14 years ago

Okay, it's clear now. Eating 100% CPU is not good of course but it's obviously not a reason of the wrong message flow, it's just something that reveals it.

The problem is that Java does not expect a situation when one AwtToolkit::MessageLoop() is nested into another. So what happens is (simplified):

  1. On AWT thread:
  2. WM_MOUSEMOVE on AWT thread calls IDragSource::GiveFeedback() in Java
  3. IDragSource::GiveFeedback() posts DRAG_MOTION to JEH (Java event handler) thread and enters a secondary message loop with AwtToolkit::MessageLoop() to wait for a reply from JEH but not block message processing.
  4. On JEH thread:
  5. DRAG_MOTION is received, an action is performed.
  6. A confirmation is sent back to AWT thread that is a message that will cause the secondary message loop to exit and restore normal message flow.
  7. On AWT thread:
  8. It just happens that the confirmation message gets queued after another WM_MOUSEMOVE.
  9. The secondary message loop picks up WM_MOUSEMOVE (instead the confirmation) and processes it first.
  10. Steps 2-6 repeat here. This means that the secondary message loop is entered for the second time, before the previous one is exited.
  11. The secondary event loop processes both confirmation messages which both raise the same breakMessageLoop flag that instructs the message loop to terminate.
  12. The inner secondary message loop sees the breakMessageLoop flag, breaks itself, resets breakMessageLoop to FALSE and returns to the outer secondary message loop.
  13. Since the flag is already reset by the inner loop, the outer one keeps rolling and nobody tells it to stop (the inner one processed both confirmation messages).

comment:7 by dmik, 14 years ago

Note that the problem exists in Windows too but seems to be hidden very well due to different timings (and in particular the absence of 100% CPU load mentioned above).

comment:8 by dmik, 14 years ago

The issue should be fixed in r238. I had to enforce a particular message order so that no messages like WM_MOUSEMOVE are processed before the secondary message loop exits. This ensures the proper message flow and also that loops don't nest.

comment:9 by dmik, 14 years ago

in r239, that is.

comment:10 by dmik, 14 years ago

Resolution: fixed
Status: newclosed

In revision 21556 in Odin I also fixed a crash that could happen when crossing the window frame with the dragged object due to the fact that Odin sends DM_DRAGOVER and other messages manually using WinSendMsg() so that some internal structures are not set up and cause later a crash when accessing the accidentally freed DRAGINFO structure.

Note: See TracTickets for help on using tickets.