Index: gnu/java/awt/peer/gtk/GtkButtonPeer.java =================================================================== RCS file: /cvs/gcc/gcc/libjava/gnu/java/awt/peer/gtk/GtkButtonPeer.java,v retrieving revision 1.8 diff -u -r1.8 GtkButtonPeer.java --- gnu/java/awt/peer/gtk/GtkButtonPeer.java 10 Feb 2004 17:12:08 -0000 1.8 +++ gnu/java/awt/peer/gtk/GtkButtonPeer.java 5 Mar 2004 22:17:08 -0000 @@ -42,6 +42,7 @@ import java.awt.Button; import java.awt.Component; import java.awt.Font; +import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.event.KeyEvent; import java.awt.peer.ButtonPeer; @@ -69,11 +70,15 @@ public void handleEvent (AWTEvent e) { - if (e.getID () == MouseEvent.MOUSE_CLICKED && isEnabled ()) + if (e.getID () == MouseEvent.MOUSE_RELEASED && isEnabled ()) { MouseEvent me = (MouseEvent) e; + Point p = me.getPoint(); + p.translate(((Component) me.getSource()).getX(), + ((Component) me.getSource()).getY()); if (!me.isConsumed () - && (me.getModifiers () & MouseEvent.BUTTON1_MASK) != 0) + && (me.getModifiers () & MouseEvent.BUTTON1_MASK) != 0 + && awtComponent.getBounds().contains(p)) postActionEvent (((Button)awtComponent).getActionCommand (), me.getModifiers ()); } Index: java/awt/Container.java =================================================================== RCS file: /cvs/gcc/gcc/libjava/java/awt/Container.java,v retrieving revision 1.34.2.2 diff -u -r1.34.2.2 Container.java --- java/awt/Container.java 27 Feb 2004 19:43:40 -0000 1.34.2.2 +++ java/awt/Container.java 5 Mar 2004 22:17:09 -0000 @@ -1553,6 +1553,9 @@ private long eventMask; private transient Component mouseEventTarget; + private transient Component pressedComponent; + private transient Component lastComponentEntered; + private transient int pressCount; LightweightDispatcher(Container c) { @@ -1568,46 +1571,37 @@ { int x = me.getX (); int y = me.getY (); - Component candidate = mouseEventTarget; - - while(candidate != null) - { - if (candidate.isShowing()) - { - // Convert our point to the candidate's parent's space. - Point cp = SwingUtilities.convertPoint(nativeContainer, x, y, candidate); - - // If the event lands inside candidate, we have a hit. - if (candidate.contains(cp.x, cp.y)) - { - // If candidate has children, we refine the hit. - if (candidate instanceof Container && - ((Container)candidate).getComponentCount() > 0) - candidate = SwingUtilities.getDeepestComponentAt(candidate, cp.x, cp.y); - break; - } - } - // If candidate isn't showing or doesn't contain point, we back out a level. - candidate = candidate.getParent(); - } - - if (candidate == null) + + // Find the candidate which should receive this event. + Component parent = nativeContainer; + Component candidate = null; + Point p = me.getPoint(); + while (candidate == null && parent != null) { - // We either lost, or never had, a candidate; acquire from our native. - candidate = - SwingUtilities.getDeepestComponentAt(nativeContainer, x, y); + candidate = + SwingUtilities.getDeepestComponentAt(parent, p.x, p.y); + if (candidate == null) + { + p = SwingUtilities.convertPoint(parent, p.x, p.y, parent.parent); + parent = parent.parent; + } } + // If the only candidate we found was the native container itself, + // don't dispatch any event at all. We only care about the lightweight + // children here. + if (candidate == nativeContainer) + candidate = null; // If our candidate is new, inform the old target we're leaving. - if (mouseEventTarget != null - && mouseEventTarget.isShowing() - && mouseEventTarget != candidate) + if (lastComponentEntered != null + && lastComponentEntered.isShowing() + && lastComponentEntered != candidate) { Point tp = SwingUtilities.convertPoint(nativeContainer, - x, y, mouseEventTarget); - MouseEvent exited = new MouseEvent (mouseEventTarget, + x, y, lastComponentEntered); + MouseEvent exited = new MouseEvent (lastComponentEntered, MouseEvent.MOUSE_EXITED, me.getWhen (), me.getModifiers (), @@ -1615,22 +1609,23 @@ me.getClickCount (), me.isPopupTrigger (), me.getButton ()); - mouseEventTarget.dispatchEvent (exited); - mouseEventTarget = null; + lastComponentEntered.dispatchEvent (exited); + lastComponentEntered = null; } // If we have a candidate, maybe enter it. if (candidate != null) { + mouseEventTarget = candidate; if (candidate.isLightweight() && candidate.isShowing() && candidate != nativeContainer - && candidate != mouseEventTarget) + && candidate != lastComponentEntered) { - mouseEventTarget = candidate; + lastComponentEntered = mouseEventTarget; Point cp = SwingUtilities.convertPoint(nativeContainer, - x, y, candidate); - MouseEvent entered = new MouseEvent (mouseEventTarget, + x, y, lastComponentEntered); + MouseEvent entered = new MouseEvent (lastComponentEntered, MouseEvent.MOUSE_ENTERED, me.getWhen (), me.getModifiers (), @@ -1638,9 +1633,29 @@ me.getClickCount (), me.isPopupTrigger (), me.getButton ()); - mouseEventTarget.dispatchEvent (entered); + lastComponentEntered.dispatchEvent (entered); } } + + if (me.getID() == MouseEvent.MOUSE_RELEASED + || me.getID() == MouseEvent.MOUSE_PRESSED && pressCount > 0 + || me.getID() == MouseEvent.MOUSE_DRAGGED) + // If any of the following events occur while a button is held down, + // they should be dispatched to the same component to which the + // original MOUSE_PRESSED event was dispatched: + // - MOUSE_RELEASED + // - MOUSE_PRESSED: another button pressed while the first is held down + // - MOUSE_DRAGGED + mouseEventTarget = pressedComponent; + else if (me.getID() == MouseEvent.MOUSE_CLICKED) + { + // Don't dispatch CLICKED events whose target is not the same as the + // target for the original PRESSED event. + if (candidate != pressedComponent) + mouseEventTarget = null; + else if (pressCount == 0) + pressedComponent = null; + } } boolean handleEvent(AWTEvent e) @@ -1651,17 +1666,36 @@ if (e instanceof MouseEvent) { MouseEvent me = (MouseEvent) e; + acquireComponentForMouseEvent(me); - // Avoid dispatching an ENTERED event twice. + // Avoid dispatching ENTERED and EXITED events twice. if (mouseEventTarget != null && mouseEventTarget.isShowing() - && e.getID() != MouseEvent.MOUSE_ENTERED) + && e.getID() != MouseEvent.MOUSE_ENTERED + && e.getID() != MouseEvent.MOUSE_EXITED) { MouseEvent newEvt = SwingUtilities.convertMouseEvent(nativeContainer, me, mouseEventTarget); mouseEventTarget.dispatchEvent(newEvt); + + switch (e.getID()) + { + case MouseEvent.MOUSE_PRESSED: + if (pressCount++ == 0) + pressedComponent = mouseEventTarget; + break; + + case MouseEvent.MOUSE_RELEASED: + // Clear our memory of the original PRESSED event, only if + // we're not expecting a CLICKED event after this. If + // there is a CLICKED event after this, it will do clean up. + if (--pressCount == 0 + && mouseEventTarget != pressedComponent) + pressedComponent = null; + break; + } } } else if (e instanceof KeyEvent && focus != null) Index: jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c =================================================================== RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c,v retrieving revision 1.19 diff -u -r1.19 gnu_java_awt_peer_gtk_GtkEvents.c --- jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c 26 Jan 2004 21:55:42 -0000 1.19 +++ jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c 5 Mar 2004 22:17:11 -0000 @@ -83,6 +83,27 @@ return result; } +static jint +state_to_awt_mods_with_button_states (guint state) +{ + jint result = 0; + + if (state & GDK_SHIFT_MASK) + result |= AWT_SHIFT_MASK; + if (state & GDK_CONTROL_MASK) + result |= AWT_CTRL_MASK; + if (state & GDK_MOD1_MASK) + result |= AWT_ALT_MASK; + if (state & GDK_BUTTON1_MASK) + result |= AWT_BUTTON1_MASK; + if (state & GDK_BUTTON2_MASK) + result |= AWT_BUTTON2_MASK; + if (state & GDK_BUTTON3_MASK) + result |= AWT_BUTTON3_MASK; + + return result; +} + /* Modifier key events need special treatment. In Sun's peer implementation, when a modifier key is pressed, the KEY_PRESSED event has that modifier in its modifiers list. The corresponding @@ -830,6 +851,7 @@ static GdkWindow *button_window = NULL; static guint button_number = -1; static jint click_count = 1; + static int hasBeenDragged; /* If it is not a focus change event, the widget must be realized already. If not, ignore the event (Gtk+ will do the same). */ @@ -895,6 +917,7 @@ click_count, (event->button.button == 3) ? JNI_TRUE : JNI_FALSE); + hasBeenDragged = FALSE; break; case GDK_BUTTON_RELEASE: { @@ -911,10 +934,12 @@ click_count, JNI_FALSE); - /* check to see if the release occured in the window it was pressed - in, and if so, generate an AWT click event */ + // Generate an AWT click event only if the release occured in the + // window it was pressed in, and the mouse has not been dragged since + // the last time it was pressed. gdk_window_get_size (event->any.window, &width, &height); - if (event->button.x >= 0 + if (! hasBeenDragged + && event->button.x >= 0 && event->button.y >= 0 && event->button.x <= width && event->button.y <= height) @@ -933,15 +958,6 @@ } break; case GDK_MOTION_NOTIFY: - (*gdk_env)->CallVoidMethod (gdk_env, peer, postMouseEventID, - AWT_MOUSE_MOVED, - (jlong)event->motion.time, - state_to_awt_mods (event->motion.state), - (jint)event->motion.x, - (jint)event->motion.y, - 0, - JNI_FALSE); - if (event->motion.state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK @@ -952,12 +968,22 @@ postMouseEventID, AWT_MOUSE_DRAGGED, (jlong)event->motion.time, - state_to_awt_mods (event->motion.state), + state_to_awt_mods_with_button_states (event->motion.state), (jint)event->motion.x, (jint)event->motion.y, 0, JNI_FALSE); + hasBeenDragged = TRUE; } + else + (*gdk_env)->CallVoidMethod (gdk_env, peer, postMouseEventID, + AWT_MOUSE_MOVED, + (jlong)event->motion.time, + state_to_awt_mods (event->motion.state), + (jint)event->motion.x, + (jint)event->motion.y, + 0, + JNI_FALSE); break; case GDK_ENTER_NOTIFY: /* We are not interested in enter events that are due to @@ -966,7 +992,7 @@ (*gdk_env)->CallVoidMethod (gdk_env, peer, postMouseEventID, AWT_MOUSE_ENTERED, (jlong)event->crossing.time, - state_to_awt_mods (event->crossing.state), + state_to_awt_mods_with_button_states (event->crossing.state), (jint)event->crossing.x, (jint)event->crossing.y, 0, @@ -980,7 +1006,7 @@ postMouseEventID, AWT_MOUSE_EXITED, (jlong)event->crossing.time, - state_to_awt_mods (event->crossing.state), + state_to_awt_mods_with_button_states (event->crossing.state), (jint)event->crossing.x, (jint)event->crossing.y, 0,