JDK-4977491 : Window state changes without notifying the listener on Win32
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 6
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2004-01-13
  • Updated: 2016-06-07
  • Resolved: 2011-03-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 b15Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
I have written an application which sets the states for the frame in the following order, after checking whether they are supported.

Frame.MAXIMIZED_BOTH
Frame.ICONIFIED
Frame.NORMAL

This results in a set of window events being triggered and the sequence of events triggered on Win XP is as follows:
======= From Listener =======================
1.OLD state:  NORMAL
2.New state:  MAXIMIZED_BOTH MAXIMIZED_VERT MAXIMIZED_HORIZ

3.OLD state:  MAXIMIZED_BOTH MAXIMIZED_VERT MAXIMIZED_HORIZ
4.New state:  MAXIMIZED_BOTH MAXIMIZED_VERT MAXIMIZED_HORIZ ICONIFIED

5.OLD state:  ICONIFIED
6.New state:  NORMAL
==============================================

When I looked at event 4,5, I am surprised to see the state being changed from MAXIMIZED_BOTH + ICONIFIED to just ICONIFIED without notifying the listener. The application has not initiated any state change that would change the state 4 to state 5. I expect the new state of the previous event and the old state of the current event to be same which is not happening in  case of WinXP. On Solaris, both state 4,5 are ICONIFIED.

This is noticed right from JDK1.4.

I have attached a sample testcase. Execute the sample testcase. If you notice the above behavior, the bug is reproduced.

Comments
SUGGESTED FIX *** /export/ap203012/d33-maxIcoMaxNormal/webrev/src/windows/native/sun/windows/awt_Frame.cpp- 2007-06-04 10:30:04.000000000 +0400 --- awt_Frame.cpp 2007-06-01 17:06:45.000000000 +0400 *** 112,121 **** --- 112,122 ---- m_proxyFocusOwner = NULL; m_actualFocusedWindow = NULL; m_iconic = FALSE; m_zoomed = FALSE; m_maxBoundsSet = FALSE; + m_forceResetZoomed = FALSE; isInManualMoveOrSize = FALSE; grabbedHitTest = 0; } *** 778,844 **** MsgRouting AwtFrame::WmSize(UINT type, int w, int h) { if (m_ignoreWmSize) { return mrDoDefault; } ! DTRACE_PRINTLN6("AwtFrame::WmSize: %dx%d,%s visible, state%s%s%s", w, h, ::IsWindowVisible(GetHWnd()) ? "" : " not", m_iconic ? " iconic" : "", m_zoomed ? " zoomed" : "", m_iconic || m_zoomed ? "" : " normal"); jint oldState = java_awt_Frame_NORMAL; ! if (m_iconic) { ! oldState |= java_awt_Frame_ICONIFIED; } ! if (m_zoomed) { ! oldState |= java_awt_Frame_MAXIMIZED_BOTH; } jint newState = java_awt_Frame_NORMAL; ! if (type == SIZE_MINIMIZED) { ! DTRACE_PRINTLN("AwtFrame::WmSize: SIZE_MINIMIZED"); ! newState |= java_awt_Frame_ICONIFIED; ! if (m_zoomed) { ! newState |= java_awt_Frame_MAXIMIZED_BOTH; ! } ! m_iconic = TRUE; } ! else if (type == SIZE_MAXIMIZED) { ! DTRACE_PRINTLN("AwtFrame::WmSize: SIZE_MAXIMIZED"); ! newState |= java_awt_Frame_MAXIMIZED_BOTH; ! m_iconic = FALSE; ! m_zoomed = TRUE; ! } ! else if (type == SIZE_RESTORED) { ! DTRACE_PRINTLN("AwtFrame::WmSize: SIZE_RESTORED"); ! m_iconic = FALSE; ! m_zoomed = FALSE; } jint changed = oldState ^ newState; if (changed != 0) { ! DTRACE_PRINTLN2("AwtFrame::WmSize: reporting state change %x -> %x", ! oldState, newState); ! // report (de)iconification to old clients ! if (changed & java_awt_Frame_ICONIFIED) { ! if (newState & java_awt_Frame_ICONIFIED) { ! SendWindowEvent(java_awt_event_WindowEvent_WINDOW_ICONIFIED); ! } else { ! SendWindowEvent(java_awt_event_WindowEvent_WINDOW_DEICONIFIED); ! } ! } ! // New (since 1.4) state change event ! SendWindowStateEvent(oldState, newState); } // If window is in iconic state, do not send COMPONENT_RESIZED event ! if (m_iconic) { ! return mrDoDefault; } return AwtWindow::WmSize(type, w, h); } --- 779,857 ---- MsgRouting AwtFrame::WmSize(UINT type, int w, int h) { if (m_ignoreWmSize) { return mrDoDefault; } ! DTRACE_PRINTLN6("AwtFrame::WmSize: %dx%d,%s visible, state%s%s%s", w, h, ::IsWindowVisible(GetHWnd()) ? "" : " not", m_iconic ? " iconic" : "", m_zoomed ? " zoomed" : "", m_iconic || m_zoomed ? "" : " normal"); + BOOL iconify = type == SIZE_MINIMIZED; + + // Note that zoom may be set to TRUE in several cases: + // 1. type == SIZE_MAXIMIZED means that either the user or + // the developer (via setExtendedState(MAXIMIZED_BOTH) + // maximizes the frame. + // 2. type == SIZE_MINIMIZED && isZoomed() means that a maximized + // frame is to be minimized. If the user minimizes a maximized + // frame, we need to keep the zoomed property TRUE. However, + // if the developer calls setExtendedState(ICONIFIED), i.e. + // w/o combining the ICONIFIED state with the MAXIMIZED state, + // we MUST RESET the zoomed property. + // The flag m_forceResetZoomed identifies the latter case. + BOOL zoom = + ( + type == SIZE_MAXIMIZED + || + (type == SIZE_MINIMIZED && isZoomed()) + ) + && !m_forceResetZoomed; + + // Set the new state and send appropriate Java event jint oldState = java_awt_Frame_NORMAL; ! if (isIconic()) { ! oldState |= java_awt_Frame_ICONIFIED; } ! if (isZoomed()) { ! oldState |= java_awt_Frame_MAXIMIZED_BOTH; } jint newState = java_awt_Frame_NORMAL; ! if (iconify) { ! newState |= java_awt_Frame_ICONIFIED; } ! if (zoom) { ! newState |= java_awt_Frame_MAXIMIZED_BOTH; } + setIconic(iconify); + setZoomed(zoom); + jint changed = oldState ^ newState; if (changed != 0) { ! DTRACE_PRINTLN2("AwtFrame::WmSize: reporting state change %x -> %x", ! oldState, newState); ! // report (de)iconification to old clients ! if (changed & java_awt_Frame_ICONIFIED) { ! if (newState & java_awt_Frame_ICONIFIED) { ! SendWindowEvent(java_awt_event_WindowEvent_WINDOW_ICONIFIED); ! } else { ! SendWindowEvent(java_awt_event_WindowEvent_WINDOW_DEICONIFIED); ! } ! } ! // New (since 1.4) state change event ! SendWindowStateEvent(oldState, newState); } // If window is in iconic state, do not send COMPONENT_RESIZED event ! if (isIconic()) { ! return mrDoDefault; } return AwtWindow::WmSize(type, w, h); } *** 1229,1310 **** AwtFrame *f = NULL; PDATA pData; JNI_CHECK_PEER_GOTO(self, ret); f = (AwtFrame *)pData; ! if (::IsWindow(f->GetHWnd())) { DASSERT(!IsBadReadPtr(f, sizeof(AwtFrame))); BOOL iconify = (state & java_awt_Frame_ICONIFIED) != 0; BOOL zoom = (state & java_awt_Frame_MAXIMIZED_BOTH) == java_awt_Frame_MAXIMIZED_BOTH; - HWND hwnd = f->GetHWnd(); - BOOL focusable = f->IsFocusableWindow(); - DTRACE_PRINTLN4("WFramePeer.setState:%s%s ->%s%s", f->isIconic() ? " iconic" : "", f->isZoomed() ? " zoomed" : "", iconify ? " iconic" : "", zoom ? " zoomed" : ""); if (::IsWindowVisible(hwnd)) { ! // Iconify first if necessary, so that for a complex state ! // transition zoom state is changed when we are iconified - to ! // reduce window flicker. ! if (!f->isIconic() && iconify) { ! if (focusable) { ! ::ShowWindow(hwnd, SW_MINIMIZE); ! } else { ! ::ShowWindow(hwnd, SW_SHOWMINNOACTIVE); ! } } ! // If iconified, handle zoom state change while/when in iconic state ! if (zoom != f->isZoomed()) { ! if (::IsIconic(hwnd)) { ! // Arrange for window to be restored to specified state ! WINDOWPLACEMENT wp; ! ::ZeroMemory(&wp, sizeof(WINDOWPLACEMENT)); ! wp.length = sizeof(WINDOWPLACEMENT); ! ::GetWindowPlacement(hwnd, &wp); ! if (zoom) { ! wp.flags |= WPF_RESTORETOMAXIMIZED; ! } else { ! wp.flags &= ~WPF_RESTORETOMAXIMIZED; ! } ! ::SetWindowPlacement(hwnd, &wp); ! } ! else { ! // Not iconified - just maximize it ! if (focusable) { ! ::ShowWindow(hwnd, zoom ? SW_SHOWMAXIMIZED : SW_RESTORE); ! } else { ! ::ShowWindow(hwnd, zoom ? SW_MAXIMIZE : SW_SHOWNOACTIVATE); ! } ! } } ! // Handle deiconify if necessary. ! if (f->isIconic() && !iconify) { ! if (focusable) { ! ::ShowWindow(hwnd, SW_RESTORE); ! } else { ! ::ShowWindow(hwnd, SW_SHOWNOACTIVATE); ! } ! } ! } ! #ifdef DEBUG ! else { ! DTRACE_PRINTLN(" not visible, just recording the requested state"); ! } ! #endif ! f->setIconic(iconify); ! f->setZoomed(zoom); } ret: env->DeleteGlobalRef(self); delete sss; --- 1242,1307 ---- AwtFrame *f = NULL; PDATA pData; JNI_CHECK_PEER_GOTO(self, ret); f = (AwtFrame *)pData; ! HWND hwnd = f->GetHWnd(); ! if (::IsWindow(hwnd)) { DASSERT(!IsBadReadPtr(f, sizeof(AwtFrame))); BOOL iconify = (state & java_awt_Frame_ICONIFIED) != 0; BOOL zoom = (state & java_awt_Frame_MAXIMIZED_BOTH) == java_awt_Frame_MAXIMIZED_BOTH; DTRACE_PRINTLN4("WFramePeer.setState:%s%s ->%s%s", f->isIconic() ? " iconic" : "", f->isZoomed() ? " zoomed" : "", iconify ? " iconic" : "", zoom ? " zoomed" : ""); if (::IsWindowVisible(hwnd)) { ! BOOL focusable = f->IsFocusableWindow(); ! ! WINDOWPLACEMENT wp; ! ::ZeroMemory(&wp, sizeof(wp)); ! wp.length = sizeof(wp); ! ::GetWindowPlacement(hwnd, &wp); ! ! // Iconify first. ! // If both iconify & zoom are TRUE, handle this case ! // with wp.flags field below. ! if (iconify) { ! wp.showCmd = focusable ? SW_MINIMIZE : SW_SHOWMINNOACTIVE; ! } else if (zoom) { ! wp.showCmd = focusable ? SW_SHOWMAXIMIZED : SW_MAXIMIZE; ! } else { // zoom == iconify == FALSE ! wp.showCmd = focusable ? SW_RESTORE : SW_SHOWNOACTIVATE; } ! if (zoom && iconify) { ! wp.flags |= WPF_RESTORETOMAXIMIZED; ! } else { ! wp.flags &= ~WPF_RESTORETOMAXIMIZED; ! } ! if (!zoom) { ! f->m_forceResetZoomed = TRUE; } ! // The SetWindowPlacement() causes the WmSize() invocation ! // which, in turn, actually updates the m_iconic & m_zoomed flags ! // as well as sends Java event (WINDOW_STATE_CHANGED.) ! ::SetWindowPlacement(hwnd, &wp); ! ! f->m_forceResetZoomed = FALSE; ! } else { ! DTRACE_PRINTLN(" not visible, just recording the requested state"); ! f->setIconic(iconify); ! f->setZoomed(zoom); ! } } ret: env->DeleteGlobalRef(self); delete sss;
31-05-2007

EVALUATION A new flag (m_forceResetZoomed) is necessary in order to unconditionally reset the MAXIMIZED state in case the developer explicitly sets the ICONIFIED state, no matter whether previously this frame was maximized or not.
31-05-2007

EVALUATION Name: osR10079 Date: 01/14/2004 The problem is that we receive incorrect WINDOW_STATE_CHANGED event after setExtendedState(Frame.ICONIFIED). After this call the state should be Frame.ICONIFIED, not (MAXIMIZED_BOTH MAXIMIZED_VERT MAXIMIZED_HORIZ ICONIFIED). because setExtendedState() should just set provided state, do not try to combine it with current state. The cause of this problem in native code. We generate events in AwtFrame::WmSize() method. But it works so if its "type" parameter is SIZE_MINIMIZED and currently the frame is maximized (m_zoomed == TRUE) treat new state as combination of ICONIFY and MAXIMAZED. And this is correct behavior when we get WM_SIZE because of user's action, but it is not correct if WM_SIZE is caused by WFramePeer.setState() call. It looks like we need one more flag for this situation :( ###@###.### Jan 14, 2004 ====================================================================== This bug should be investigated with other toplevel states/ zoomed windows bugs. Fixing it would be too risky for mustang. ###@###.### 2005-07-07 15:02:21 GMT
07-07-2005

CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mustang
18-08-2004