JDK-4869912 : REGRESSION: MouseReleased Event is triggered in JFrame behind a closing JFrame
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 6
  • Priority: P3
  • Status: Closed
  • Resolution: Won't Fix
  • OS: windows_nt,windows_2000
  • CPU: x86
  • Submitted: 2003-05-27
  • Updated: 2011-03-29
  • Resolved: 2006-12-12
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Description
Name: jk109818			Date: 05/27/2003


FULL PRODUCT VERSION :
java version "1.4.1_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_02-b06)
Java HotSpot(TM) Client VM (build 1.4.1_02-b06, mixed mode)

FULL OS VERSION :
Windows NT Version 4.0

A DESCRIPTION OF THE PROBLEM :
When closing a JFrame by double clicking the icon in the upper left corner of the JFrame, a MouseReleased event is triggered on any JFrame behind the closing JFrame.  The mouse event should be captured by the closing JFrame.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Open a JFrame
Open another JFrame, making sure the icon in the left corner of the title bar is inside the first JFrame.
Double click on the second JFrame's icon in the left corner of the title bar.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The closing frame absorbs all the mouse events from the double click.
ACTUAL -
The MouseReleased event from the double click is sent to the JFrame below the closing JFrame.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package com.doesntwork.frametest;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class StartFrame extends JFrame
{
    public StartFrame()
    {
        init();
    }

    private void init()
    {
        JPanel clickCountPanel = new JPanel();
		clickCountPanel.addMouseListener(new MouseListener()
        {
            public void mouseClicked(MouseEvent me)
            {
                System.out.println("Mouse Clicked");
            }
            public void mouseEntered(MouseEvent me)
            {
            }
            public void mouseExited(MouseEvent me)
            {
            }
            public void mousePressed(MouseEvent me)
            {
                System.out.println("Mouse Pressed");
            }
            public void mouseReleased(MouseEvent me)
            {
                System.out.println("Mouse Released " + me.getComponent());
            }
        });

        this.setContentPane(clickCountPanel);

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(200,200);
        this.setVisible(true);

        JFrame smallFrame = new JFrame();
        smallFrame.setSize(100,100);
        smallFrame.setVisible(true);
        smallFrame.setLocation(50,50);
        
    }

    public static void main(String[] args)
    {
        StartFrame frame = new StartFrame();
    }
}
---------- END SOURCE ----------

Release Regression From : 1.3.1_06
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

(Review ID: 185968) 
======================================================================

Comments
EVALUATION The fix was rolled back as it introduces another kind of incompatibility. We decided to stick with the current behavior model as it fits the native Windows applications.
12-12-2006

SUGGESTED FIX *** /tmp/geta22037 2005-08-31 19:32:11.000000000 +0400 --- awt_Component.h 2005-08-31 18:47:40.000000000 +0400 *************** *** 98,104 **** static jmethodID replaceSurfaceDataLaterMID; static const UINT WmAwtIsComponent; ! AwtComponent(); virtual ~AwtComponent(); --- 98,104 ---- static jmethodID replaceSurfaceDataLaterMID; static const UINT WmAwtIsComponent; ! static BOOL shouldSkipNextMouseReleasedEvent; AwtComponent(); virtual ~AwtComponent(); *** /tmp/geta21726 2005-08-31 19:30:39.000000000 +0400 --- awt_Component.cpp 2005-08-31 19:00:57.000000000 +0400 *************** *** 201,206 **** --- 201,207 ---- CriticalSection windowMoveLock; BOOL windowMoveLockHeld = FALSE; BOOL windowSizing = FALSE; + BOOL AwtComponent::shouldSkipNextMouseReleasedEvent = FALSE; /************************************************************************ * AwtComponent methods *************** *** 1263,1269 **** LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { JNILocalFrame lframe(AwtToolkit::GetEnv(), 10); ! SpyWinMessage(GetHWnd(), message, (message == WM_AWT_RELEASE_ALL_DCS) ? TEXT("Disposed Component") : GetClassName()); --- 1264,1270 ---- LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { JNILocalFrame lframe(AwtToolkit::GetEnv(), 10); ! POINT p = { 0, 0 }; SpyWinMessage(GetHWnd(), message, (message == WM_AWT_RELEASE_ALL_DCS) ? TEXT("Disposed Component") : GetClassName()); *************** *** 1428,1433 **** --- 1429,1442 ---- mr = WmShowWindow(static_cast<BOOL>(wParam), static_cast<UINT>(lParam)); break; case WM_SYSCOMMAND: + ::GetCursorPos(&p); + + if( wParam == SC_CLOSE && ::SendMessage(GetHWnd(), WM_NCHITTEST, 0, + MAKELPARAM(p.x, p.y)) == HTSYSMENU) { + AwtComponent::shouldSkipNextMouseReleasedEvent = TRUE; + } + mr = WmSysCommand(static_cast<UINT>(wParam & 0xFFF0), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; *************** *************** *** 2490,2501 **** { MSG msg; InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y); ! SendMouseEvent(java_awt_event_MouseEvent_MOUSE_RELEASED, nowMillisUTC(), ! x, y, GetJavaModifiers(), clickCount, ! (GetButton(button) == java_awt_event_MouseEvent_BUTTON3 ? ! TRUE : FALSE), GetButton(button), &msg); ! /* * If no movement, then report a click following the button release */ --- 2499,2515 ---- { MSG msg; InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y); + ! if (!AwtComponent::shouldSkipNextMouseReleasedEvent){ ! SendMouseEvent(java_awt_event_MouseEvent_MOUSE_RELEASED, nowMillisUTC(), ! x, y, GetJavaModifiers(), clickCount, ! (GetButton(button) == java_awt_event_MouseEvent_BUTTON3 ? ! TRUE : FALSE), GetButton(button), &msg); ! } else { ! AwtComponent::shouldSkipNextMouseReleasedEvent = FALSE; ! } /* * If no movement, then report a click following the button release */
31-08-2005

SUGGESTED FIX *** /tmp/geta29559 2005-07-08 18:05:18.000000000 +0400 --- awt_Component.h 2005-07-08 18:04:17.000000000 +0400 *************** *** 98,103 **** --- 98,105 ---- static jmethodID replaceSurfaceDataLaterMID; static const UINT WmAwtIsComponent; + BOOL shouldSkipNextMouseReleasedEvent; AwtComponent(); virtual ~AwtComponent(); *** /tmp/geta29569 2005-07-08 18:05:58.000000000 +0400 --- awt_Component.cpp 2005-07-08 18:04:56.000000000 +0400 *************** *** 1259,1264 **** --- 1259,1265 ---- LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { JNILocalFrame lframe(AwtToolkit::GetEnv(), 10); + POINT p = { 0, 0 }; SpyWinMessage(GetHWnd(), message, (message == WM_AWT_RELEASE_ALL_DCS) ? TEXT("Disposed Component") : GetClassName()); *************** *** 1423,1428 **** --- 1424,1434 ---- mr = WmShowWindow(static_cast<BOOL>(wParam), static_cast<UINT>(lParam)); break; case WM_SYSCOMMAND: + ::GetCursorPos(&p); + if( ::SendMessage(GetHWnd(), WM_NCHITTEST, 0, + MAKELPARAM(p.x, p.y)) == HTSYSMENU) { + shouldSkipNextMouseReleasedEvent = TRUE; + } mr = WmSysCommand(static_cast<UINT>(wParam & 0xFFF0), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); break; *************** *** 2463,2473 **** { MSG msg; InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y); ! ! SendMouseEvent(java_awt_event_MouseEvent_MOUSE_RELEASED, nowMillisUTC(), ! x, y, GetJavaModifiers(), clickCount, ! (GetButton(button) == java_awt_event_MouseEvent_BUTTON3 ? ! TRUE : FALSE), GetButton(button), &msg); /* * If no movement, then report a click following the button release --- 2469,2482 ---- { MSG msg; InitMessage(&msg, lastMessage, flags, MAKELPARAM(x, y), x, y); ! if (!shouldSkipNextMouseReleasedEvent){ ! SendMouseEvent(java_awt_event_MouseEvent_MOUSE_RELEASED, nowMillisUTC(), ! x, y, GetJavaModifiers(), clickCount, ! (GetButton(button) == java_awt_event_MouseEvent_BUTTON3 ? ! TRUE : FALSE), GetButton(button), &msg); ! } else { ! shouldSkipNextMouseReleasedEvent = FALSE; ! } /* * If no movement, then report a click following the button release ###@###.### 2005-07-08 14:12:11 GMT
08-07-2005

EVALUATION Targeting mustang. ###@###.### 2003-06-04 Name: ssR10077 Date: 06/05/2003 Bug is not reproducible on W2K and XP. And NT is almost EOL. ====================================================================== I could see it on my Win2000 PC right from JDK1.4.0 till current JDK6.0b38. Seems that this is because of shifting the moment when Toplevel (Window, Frame, Dialog) decides to be closed. It also could be related to double click handling. See awt_component.cpp. Should check 1) whether this problem Win32-specific 2) if pure-AWT test shows the same results ###@###.### 2005-06-03 10:52:01 GMT This is win32 specific problem. The root of this is in windows native behaviour. If you click a mouse twice on the title bar in order to close current window you may see that the window hides when you _press_ the mouse second time. This is why the underlying window receives all events generated after the second mouse press. On Linux WM window closes itself once you releases mouse on second click. This is the difference between win32 and Linux. Closing a window with the second MousePress is Win32 native behaviour. We may worksround it by using newly introduced variable shouldSkipNextMouseReleasedEvent which will be set to TRUE is mouse was pressed in SYSTEMMENU area in the TitleBar of the Frame. This might be done by additional handling of WM_SYSCOMMAND message in WindowProc(), sending WM_NCHITTEST with current coordinates as lParam and checking if the area under the mouse is HTSYSMENU. Then, when we are receiving WM_MOUSEUP we may consume MOUSE_RELEASE event if shouldSkipNextMouseReleasedEvent is TRUE. ###@###.### 2005-07-08 14:12:10 GMT
08-07-2005

CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mustang
17-09-2004