Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4083025

mouseDragged events don't always come from the component where drag originated

XMLWordPrintable

    • x86
    • windows_nt

      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)
      ======================================================================

            bchristi Brent Christian
            ggrahamsunw Gregory Graham (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: