JDK-4083025 : mouseDragged events don't always come from the component where drag originated
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.1.4,1.1.6,1.1.8_003,1.2.2,1.3.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_nt
  • CPU: x86
  • Submitted: 1997-10-01
  • Updated: 2001-11-29
  • Resolved: 2001-11-29
Related Reports
Duplicate :  
Relates :  
Relates :  
Description
orig synopsis:  "several mouse event bugs"

Name: ggC50526			Date: 10/01/97

/*
The following test program demonstrates some serious bugs in java event
management under Windows NT, as well as various inconsistencies between
the Solaris and NT platforms.

The program creates a frame containing various components and logs all
generated mouse events.

1) Unexpected, unbalanced mousePressed events are generated when dragging
   out of some components.
   
   To reproduce:
     Position the cursor in either the red Button or the green Label.
     Press the mouse button, drag into the white background, and release.
     As the cursor leaves the Button or Label an inappropriate
     mousePressed event is generated. When the mouse button is released
     a single mouseReleased event is generated, despite there having been
     two prior mousePressed events. Note that in the case of the Button
     all three events are from the Button while in the case of the Label
     the second mousePressed and the mouseReleased come from the
     background Frame.
   
   Workaround:
     Way too ugly to describe.
     
   Comments:
     This is a very serious problem because it breaks the model of "what
     goes down must come up". The complexity of event handling gets
     totally out of hand if it cannot be assumed that every mousePressed
     will eventually be followed by a mouseReleased from the same source.

2) MouseDragged events don't always come from the component where the
   drag originated.
   
   To reproduce:
     Position the cursor in the green Label. Press the mouse button and
     drag into the white background. When the cursor leaves the Label
     the mouseDragged events stop coming from the Label and begin to
     come from the background Frame.
   
   Workaround:
     Again, a convoluted workaround is possible, but it's terrible to
     have to install mouseMotionListeners on components other than the
     one for which drag operations are to be supported.
     
   Comments:on Solaris working 
     We are aware that there are open bug reports on this problem but
     are mentioning it to stress the importance of getting this fixed.
     The principle that mouseDragged events (and the subsequent
     mouseReleased) come from the originating component is very useful
     for good modular event management but loses much of its value if
     chewing gum and baling wire have to be used to handle a few broken
     cases.

3) Spurious mouseClicked events are generated under certain circumstances.

   To reproduce:
     Position the cursor in the white background area. Press the mouse
     button, drag into either the red Button or the green Label, and
     release. Move the cursor back to the white background. As the cursor
     leaves the Button or Label an inappropriate mouseClicked event is
     generated.
   
   Workaround:
     Ignore mouseClicked events not preceded by a mousePressed at the
     same location.

   Comments:   
      More ugly platform-specific code...
     
4) MouseEntered events generated in wrong coordinate system.

   To reproduce:
      Move the cursor into and out of various components. MouseEntered
      events generated when moving to or from the Button or Label
      components apparently have their locations referenced to the
      coordinate system of the component just exited.
      
   Workaround:
      Haven't looked for one.
    
   Comments:
      This is obviously broken behavior but isn't a big deal for us
      since at this point it doesn't affect our application work. It
      was observed incidentally in the course of investigating the above.
      
The bugs listed above have been replicated on several versions of NT JDK
1.1 and 1.2 (up to 1.2J). They have not been observed in any version of
the Solaris JDK. We haven't tried any of this on Win95.

All the bugs listed above vary depending on the particular components
used. In these cases it's pretty easy to identify which variations are
clearly broken. However, there is a more general concern about the
inconsistent management of events across platforms and across various
components on the same platform. Observe mouseEntered and mouseExited
events with this program during moves and drags on NT vs Solaris for 
several examples. With the exceptions documented above, most of the
variations aren't clearly wrong in their own context, but is is
absolutely wrong for them to vary so much. Unless and until a uniform
set of event distribution rules is specified and enforced across all
platforms we'll have to settle for "write once, run anywhere, so long
as you don't do anything too fancy".

Alan Buchanan
GE Medical Systems (HJ licensee)
###@###.###
*/

import java.awt.*;
import java.awt.event.*;

public class	EventTest
{
public static void	main( String argv[] )
	{
	frame_.setLayout( null );
	frame_.setBounds( 99, 99, 350, 150 );
	frame_.setBackground( Color.white );
	
	frame_.addMouseListener      ( ear_ );
	frame_.addMouseMotionListener( ear_ );

	addComponent( new Button(), Color.red,    50,  50 );
	addComponent( new Label(),  Color.green, 150,  50 );
	addComponent( new Light(),  Color.blue,  250,  50 );

 	frame_.addWindowListener( new WindowAdapter()
		{ public void windowClosing( WindowEvent e ) { System.exit(0); } 
} );

	frame_.setVisible( true );
	}

private static void	addComponent( Component c, Color color, int x, int y )
	{
	c.setBackground( color );
	c.setBounds( x, y, 50, 50 );
	c.addMouseListener      ( ear_ );
	c.addMouseMotionListener( ear_ );
	frame_.add( c );
	}

static Frame	frame_ = new Frame();
static MouseEar	ear_   = new MouseEar();
} // EventTest

class	Light		extends		Component
{
public void paint( Graphics g )
	{
	g.setColor( getBackground() );
	g.fillRect( 0, 0, getSize().width, getSize().height );
	}
} // Light

class	MouseEar	implements	MouseListener, MouseMotionListener
{
public void	mousePressed ( MouseEvent e )	{ mouseTrap( e, "press"   ); }
public void	mouseReleased( MouseEvent e )	{ mouseTrap( e, "release" ); }
public void	mouseClicked ( MouseEvent e )	{ mouseTrap( e, "click"   ); }
public void	mouseEntered ( MouseEvent e )	{ mouseTrap( e, "enter"   ); }
public void	mouseExited  ( MouseEvent e )	{ mouseTrap( e, "exit"    ); }
public void	mouseDragged ( MouseEvent e )	{ mouseTrap( e, "drag"    ); }
public void	mouseMoved   ( MouseEvent e )	{ mouseTrap( e, "move"    ); }

private void	mouseTrap( MouseEvent event, String id )
	{
	if( last_.id_.equals( id )
	 && last_.event_.getSource() == event.getSource()
	 && ( id.equals( "drag" ) || id.equals( "move" ) ) )
	 	{
		System.out.print( id.equals( "drag" ) ? "=" : "-" );
		last_ = new EventStash( event, id, false );
		return;
		}

	if( !last_.done_ )
		System.out.print( s( last_.event_.getPoint() ) );
		
	Component c = (Component)event.getSource();
	String    s = c.getClass().getName();
	s = s.substring( s.lastIndexOf( "." ) + 1 )
	  + ( ( c instanceof Frame ) ? "\t" : "@" + s( c.getLocation() ) );

	System.out.print( "\n" + id + "\t" + s + "\t" + s( event.getPoint() ) );

	last_ = new EventStash( event, id, true );
	}

private String	s( Point p )
	{ return "" + p.x + "," + p.y; }

private EventStash	last_ = new EventStash( null, "", true );
} // MouseEar

class	EventStash
{
public MouseEvent	event_;
public String		id_;
public boolean		done_;

public	EventStash( MouseEvent event, String id, boolean done )
	{
	event_ = event;
	id_    = id;
	done_  = done;
	}
} // EventStash

company - GE Medical Systems , email - ###@###.###
======================================================================


phil.race@eng 1997-11-06

BUG #1 SPURIOUS MOUSE UPs/DOWNs/CLICKs
--------------------------------------

This is points (1) and (3) from the original submitter


awt_Toolkit.cpp has a variable m_mouseDown, which is apparently used
to track mouse state, to detect missing events

For instance if a mouse move event is seen in which a mouse button
is DOWN, but no mouse button press event was seen we must have
missed the mouse press.

If mouse state is not what is expected the code "synthesises"
the missing event, ostensibly to ensure that AWT components do
not miss events which could cause them to "lock" into the wrong
state : such as an AWT button not bring redrawn in the right way
for button state.

1) I removed the synthesis code and I haven't seen this problem myself
under NT 4.0, unfortunately, I have no idea how this effect was
previously reproduced anyway.

2) BUT the logic is flawed, in at least one way.
The check on button state is done ONLY if we have just transitioned
into an AWT window/component from a different AWT window/component or
a non-java window.

The logic is as follows:-
   // Look for mouse transitions between windows & create
    // MouseExit & MouseEnter messages
    if (mouseComp != m_lastMouseOver) {

....

 if (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST) {
            if (msg.wParam&(MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) {
                if (!m_mouseDown &&
                    msg.message != WM_LBUTTONDOWN &&
                    msg.message != WM_RBUTTONDOWN &&
                    msg.message != WM_MBUTTONDOWN &&
                    p) {
                    p->SendMessage(WM_LBUTTONDOWN, msg.wParam, msg.lParam);
                }
                m_mouseDown = TRUE;
    }

This means
 + IF the mouse moved to a different window
 + AND we have a mouse event
 + AND we don't know the mouse is down
 + AND some button is pressed
 + AND this isn't the button press event itself
 + Then - hey we must have missed it.
 

i.e. we only set m_mouseDown = TRUE on window transitions!

Suppose we have a button in a window(frame)
If we press the mouse on the window b/g and drag into the button,
then the above logic will suppose we missed the event.

This is wrong. The button press was detected, but took place
on a different component.

The 1.1.4 code will generate the mouse down and everything after that is
just not worth analysing ..

So: My fix is to remove this code entirely unless someone can demonstrate
that it serves any useful purpose. Certainly removinf it did no harm
I did only limited testing and only under NT4.0 but all the
cases I can think of: such as doing the press & release over some other
non-java window seem fine.

But this is all now moot as this is fixed as a result of the work tou
fix bug 4038721.

In 1.1.4 we would generate the mouse up/down only if the mouse
was over a different component than last time.

In 1.1.5 that part of the condition is ignored and we always check button
state.

This specifically addresses the problem I identified, but speaking
to the bug fix implementor, he does not know why the mouse event
check is there at all either.

#####################

BUG #2 Dragging not working on all components
---------------------------------------------

This is point (2) from the original submitter.

When the mouse is pressed and you move from a component the mouse
should remain associated with it until the button is released

This is happening for Buttons, and light weight components

For Labels (and may be other stuff?) we see a different behaviour

Windows issues the mouse move events to the Label ONLY SO LONG AS the
pointer is over the Label, once it leaves the Label to a new component
(eg window b/g) , the new component gets the events, even if you re-enter
the label.

This seems to be because Labels don't automatically "capture" the mouse
for you

The blue canvas in bugid 4083025 works because awt_Canvas.cpp explictly
captures and releases the mouse
adding the same code in to Label seems to have the desired effect.

There are probably other such cases but I don't know what they are ..


BUG #3 Entering a component: mouse position coordinate system
-------------------------------------------------------------

This is point (4) from the original submitter

There is a bug in the mouse enter position if the mouse is not dragged
or otherwise captured on a component when it enters the new component.

The bug occurs in AwtToolkit::PreProcessMouseMsg() because the value
in mouseLParam is converted to the coordinate space of the component
just exited, for synthesising the EXIT event, but then is used in this
inappropriate "mode" when synthesising the ENTER event.
In the drag case it is recalculated, but in the move case the logic
says that since the component on whichthe message was delivered and the
mouse component (just entered) are the same, the coordinates don't need
transforming. Well .. this was true when you entered the method, but we
just overwrote that value!

======================================================================
Name: mc57594			Date: 11/15/99
See #2 above: MouseDragged events don't always come from the component where the drag originated.

The following program is visualizing the bug in the console. (It writes the source of the mouseDragged event to the console)
?
If you start a dragging operation over the button or the frame (in the center area) the source of the dragging event will be the component where you pressed the mouse button.
If you starts it over the label the source of the dragging will be the component currently below the cursor.
?
As I recently found the List class also works incorrectly. Maybe this is an other bug, but probably the same, because it produces exactly the same result.
You can check this with the test program too.

OS: WIN NT 4.0
JDK 1.2.2
?
///////////// the test code /////////////
?
import java.awt.*;
import java.awt.event.*;
?
public class test? implements MouseMotionListener
{
??? public static void main(String args[])
??? {
??????? test t=new test();
??????? Frame frame=new Frame();
??????? Label l1=new Label("label1");
??????? List l2=new List();
??? ??? Button l3 =new Button("button");
??????? frame.add(l1,"North");
??????? frame.add(l2,"East");
??????? frame.add(l3,"West");
??????? frame.setBounds(0,0,200,200);
??????? frame.addMouseMotionListener(t);
??????? l1.addMouseMotionListener(t);
??????? l2.addMouseMotionListener(t);
??????? l3.addMouseMotionListener(t);
??????? frame.setVisible(true);
??? }
?
??? public void mouseMoved(MouseEvent event)
??? {
??? }
??? public void mouseDragged(MouseEvent event)
??? {
??????? System.out.println("DRAGGING -"+event.getSource());
??? }
}
?
(Review ID: 96836)
======================================================================

Comments
WORK AROUND Name: ggC50526 Date: 10/01/97 see comments in code ======================================================================
11-06-2004

SUGGESTED FIX Points 1) and 3) are fixed by the fix to bug 4038721. 2) MouseDragged events don't always come from the component where the drag originated. Add the following code to src/win32/sun/windows/awt_Label.cpp MsgRouting AwtLabel::WmMouseMove(UINT flags, int x, int y) { // First mouse move will be ignored, since m_dragged isn't set until // AwtComponent::WmMouseDown is called. This is on purpose, so that // frame buttons aren't interfered with. if (m_dragged && ::GetCapture() != GetHWnd()) { ::SetCapture(GetHWnd()); } return AwtComponent::WmMouseMove(flags, x, y); } MsgRouting AwtLabel::WmMouseUp(UINT flags, int x, int y, int button) { ::ReleaseCapture(); return AwtComponent::WmMouseUp(flags, x, y, button); } And declare the methods in awt_Label.h virtual MsgRouting WmMouseMove(UINT flags, int x, int y); virtual MsgRouting WmMouseUp(UINT flags, int x, int y, int button); 4) MouseEntered events generated in wrong coordinate system. The bug occurs in AwtToolkit::PreProcessMouseMsg() because the value in mouseLParam is converted to the coordinate space of the component just exited, for synthesising the EXIT event, but then is used in this inappropriate "mode" when synthesising the ENTER event. In the drag case it is recalculated, but in the move case the logic says that since the component on whichthe message was delivered and the mouse component (just entered) are the same, the coordinates don't need transforming. Well .. this was true when you entered the method, but we just overwrote that value! in src/win32/sun/windows/awt_Toolkit.cpp we have if (mouseComp) { if (p && mouseComp && p != mouseComp) { // hit bug if true // .. do the transform and it'll be OK } mouseComp->SendMessage(WM_AWT_MOUSEENTER, mouseWParam, mouseLParam) Suggested fix: right after sending the exit message reset the value in mouseLParam by adding the line:- mouseLParam = msg.lParam;
11-06-2004

EVALUATION One aspect of the problem (issue 2 in the description) has been fixed with 4035189. robi.khan@eng 1998-05-06 Name: ksT78225 Date: 03/30/99 Mohamed Sulthan( ###@###.###) 30thMarch 1999 Solaris Result.(Tested with 1.2fcs-I) ------------------------------------- Bug is not reproducible in Solaris sparc & x86. ( Verified with Both Mouse Left&Right Button ) Win32 Result(Tested with JDK 1.2-V) ----------------------------------- Bug#1 ***** BUTTON :The bug is reproducible when we use MouseRightButton. ( In appropriate MouseReleased event is generated. ie. single 'MouseReleased' event is generated for the Frame, not for the Button ) The bug is not reproducible when we use MouseLeftButton. ( Appropriate MousePressed and Released event is generated for the Button.) LABEL:The bug is reproducible when we use both MouseRight & Left Button. ( In appropriate MouseReleased event is generated. ie. single 'MouseReleased' event is generated for the Frame, not for the Label ) There are two testcases written for Bug#1 1.ButtonMousePressedReleasedTest.java 2.LabelMousePressedReleasedTest.java Bug#2 ***** The bug is reproducible when we use both the MouseLeft & Right buttons. (MouseDragged events don't always come from the component where the drag originated. ie. 'MouseDragged' events are coming for both the Label and the Frame') Testcase name is, LabelMouseDraggedTest.java Bug#3 ***** BUTTON:The Bug is not reproducible.Checked with Both MouseLeft and Right Button. LABEL: The Bug is not reproducible.Checked with Both MouseLeft and Right Button. There are two tetscases written for bug#3. 1.ButtonMouseClickedTest.java 2.LabelMouseClickedTest.java Bug#4 ***** I feel RFE. ====================================================================== Name: ksT78225 Date: 03/31/99 Mohamed Sulthan( ###@###.###) 30thMarch 1999 Solaris Result.(Tested with 1.2fcs-I) ------------------------------------- Bug is not reproducible in Solaris sparc & x86. ( Verified with Both Mouse Left&Right Button ) Win32 Result(Tested with JDK 1.2-V) ----------------------------------- Bug#1 ***** BUTTON :The bug is reproducible when we use MouseRightButton. ( In appropriate MouseReleased event is generated. ie. single 'MouseReleased' event is generated for the Frame, not for the Button ) The bug is not reproducible when we use MouseLeftButton. ( Appropriate MousePressed and Released event is generated for the Button.) LABEL:The bug is reproducible when we use both MouseRight & Left Button. ( In appropriate MouseReleased event is generated. ie. Single'MouseReleased' event is generated for the Frame, not for the Label ) There are two testcases written for Bug#1 1.ButtonMousePressedReleasedTest.java 2.LabelMousePressedReleasedTest.java Bug#2 ***** The bug is reproducible when we use both the MouseLeft & Right buttons. (MouseDragged events don't always come from the component where the drag originated. ie.'MouseDragged' events are coming for both the Label and the Frame') Testcase name is, LabelMouseDraggedTest.java Bug#3 ***** BUTTON:The Bug is not reproducible.Checked with Both MouseLeft and Right Button. LABEL: The Bug is not reproducible.Checked with Both MouseLeft and Right Button. There are two tetscases written for bug#3. 1.ButtonMouseClickedTest.java 2.LabelMouseClickedTest.java Bug#4 ***** I feel RFE. ====================================================================== 6/12/2000 kevin.ryan@eng -- as of 1.1.8_003 and 1.3.0-C, only #2 is still reproducible. Thus, the synopsis has been revised to note ONLY point #2. #2 is reproducible ONLY for the Label (which fails to capture the drag). If you press in the Label and drag out of it, drag events start going to a different component (e.g., the Frame) as soon as you leave the Label. Separately, applications that want to support drag with the right mouse button will fail. An earlier fix for this problem (see #4035189) was made using a win32 SetCapture() on the left mouse button (only). --- This was fixed in merlin by 4327623. It now works for all buttons. Closing as a duplicate. ###@###.### 2001-11-28
28-11-2001