Make GetSystemMenu respect CS_NOCLOSE, add a test case

Dmitry Timoshkov dmitry at baikal.ru
Tue Mar 29 05:08:55 CST 2005


Hello,

this is another attempt to revive an old patch for CS_NOCLOSE. A test under
Windows shows that if CS_NOCLOSE style is set a window does not have Close
item in the system menu, and in that case Close button on the window caption
is grayed. The tests show that Windows does not send WM_WINDOWPOSCHANGING
from EnableMenuItem(), but a window doesn't receive WM_NCPAINT either.
In an old mail Alexandre suggested to use RedrawWindow(RDW_FRAME) until
we find an app that depends on the exact Windows behaviour.

Changelog:
    Dmitry Timoshkov <dmitry at codeweavers.com>
    - Make GetSystemMenu respect CS_NOCLOSE.
    - EnableMenuItem should not generate WM_WINDOWPOSCHANGING message.
    - Make nonclient code check for presence of SC_CLOSE, not CS_NOCLOSE
    window class style.
    - Add a test case.

diff -up cvs/hq/wine/dlls/user/menu.c wine/dlls/user/menu.c
--- cvs/hq/wine/dlls/user/menu.c	2005-03-27 14:36:45.000000000 +0900
+++ wine/dlls/user/menu.c	2005-03-29 18:32:43.000000000 +0900
@@ -380,6 +380,9 @@ HMENU MENU_GetSysMenu( HWND hWnd, HMENU 
 
 	if (hPopupMenu)
 	{
+            if (GetClassLongW(hWnd, GCL_STYLE) & CS_NOCLOSE)
+                DeleteMenu(hPopupMenu, SC_CLOSE, MF_BYCOMMAND);
+
 	    InsertMenuW( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION,
                          (UINT_PTR)hPopupMenu, NULL );
 
@@ -3254,9 +3257,8 @@ UINT WINAPI EnableMenuItem( HMENU hMenu,
 	    if (!(parentMenu = MENU_GetMenu(menu->hSysMenuOwner)))
 		return (UINT)-1;
 
-	    /* Refresh the frame to reflect the change*/
-	    SetWindowPos(parentMenu->hWnd, 0, 0, 0, 0, 0,
-		         SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
+            /* Refresh the frame to reflect the change */
+            RedrawWindow(parentMenu->hWnd, NULL, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
 	}
     }
 
diff -up cvs/hq/wine/dlls/user/tests/msg.c wine/dlls/user/tests/msg.c
--- cvs/hq/wine/dlls/user/tests/msg.c	2005-03-27 14:36:46.000000000 +0900
+++ wine/dlls/user/tests/msg.c	2005-03-29 19:36:45.000000000 +0900
@@ -2849,6 +2849,47 @@ static void test_showwindow(void)
     flush_sequence();
 }
 
+static void test_sys_menu(HWND hwnd)
+{
+    HMENU hmenu;
+    UINT state;
+
+    /* test existing window without CS_NOCLOSE style */
+    hmenu = GetSystemMenu(hwnd, FALSE);
+    ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
+
+    state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
+    ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
+    ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
+
+    EnableMenuItem(hmenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
+    ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
+
+    state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
+    ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
+    ok((state & (MF_DISABLED | MF_GRAYED)) == MF_GRAYED, "wrong SC_CLOSE state %x\n", state);
+
+    EnableMenuItem(hmenu, SC_CLOSE, 0);
+    ok_sequence(WmEmptySeq, "WmEnableMenuItem", FALSE);
+
+    state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
+    ok(state != 0xffffffff, "wrong SC_CLOSE state %x\n", state);
+    ok(!(state & (MF_DISABLED | MF_GRAYED)), "wrong SC_CLOSE state %x\n", state);
+
+    /* test new window with CS_NOCLOSE style */
+    hwnd = CreateWindowExA(0, "NoCloseWindowClass", NULL, WS_OVERLAPPEDWINDOW,
+                           100, 100, 200, 200, 0, 0, 0, NULL);
+    ok (hwnd != 0, "Failed to create overlapped window\n");
+
+    hmenu = GetSystemMenu(hwnd, FALSE);
+    ok(hmenu != 0, "GetSystemMenu error %ld\n", GetLastError());
+
+    state = GetMenuState(hmenu, SC_CLOSE, MF_BYCOMMAND);
+    ok(state == 0xffffffff, "wrong SC_CLOSE state %x\n", state);
+
+    DestroyWindow(hwnd);
+}
+
 /* test if we receive the right sequence of messages */
 static void test_messages(void)
 {
@@ -2912,6 +2953,9 @@ static void test_messages(void)
     SetWindowPos( hwnd, 0, 0, 0, 200, 200, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE );
     ok_sequence(WmSWP_ResizePopupSeq, "SetWindowPos:ResizePopup", FALSE );
 
+    test_sys_menu(hwnd);
+
+    flush_sequence();
     DestroyWindow(hwnd);
     ok_sequence(WmDestroyOverlappedSeq, "DestroyWindow:overlapped", FALSE);
 
@@ -4650,6 +4694,10 @@ static BOOL RegisterWindowClasses(void)
     cls.lpszClassName = "SimpleWindowClass";
     if(!RegisterClassA(&cls)) return FALSE;
 
+    cls.style = CS_NOCLOSE;
+    cls.lpszClassName = "NoCloseWindowClass";
+    if(!RegisterClassA(&cls)) return FALSE;
+
     ok(GetClassInfoA(0, "#32770", &cls), "GetClassInfo failed\n");
     cls.style = 0;
     cls.hInstance = GetModuleHandleA(0);
diff -up cvs/hq/wine/windows/nonclient.c wine/windows/nonclient.c
--- cvs/hq/wine/windows/nonclient.c	2005-03-29 14:25:52.000000000 +0900
+++ wine/windows/nonclient.c	2005-03-29 18:34:30.000000000 +0900
@@ -891,9 +891,9 @@ static void  NC_DrawCaption( HDC  hdc, R
 	hSysMenu = GetSystemMenu(hwnd, FALSE);
 	state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
 
-	/* Draw a grayed close button if disabled and a normal one if SC_CLOSE is not there */
+	/* Draw a grayed close button if disabled or if SC_CLOSE is not there */
 	NC_DrawCloseButton (hwnd, hdc, FALSE,
-			    ((((state & MF_DISABLED) || (state & MF_GRAYED))) && (state != 0xFFFFFFFF)));
+			    (state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF));
 	r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
 
 	if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
@@ -1459,9 +1459,17 @@ LONG NC_HandleNCLButtonDblClk( HWND hwnd
 	break;
 
     case HTSYSMENU:
-        if (!(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE))
+        {
+            HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
+            UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
+ 
+            /* If the item close of the sysmenu is disabled or not there do nothing */
+            if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
+                break;
+
             SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
-	break;
+            break;
+        }
 
     case HTHSCROLL:
         SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
diff -up cvs/hq/wine/windows/win.c wine/windows/win.c
--- cvs/hq/wine/windows/win.c	2005-03-27 14:36:51.000000000 +0900
+++ wine/windows/win.c	2005-03-29 19:51:15.000000000 +0900
@@ -1023,7 +1023,7 @@ static HWND WIN_CreateWindowEx( CREATEST
     wndPtr->userdata       = 0;
     wndPtr->hIcon          = 0;
     wndPtr->hIconSmall     = 0;
-    wndPtr->hSysMenu       = (wndPtr->dwStyle & WS_SYSMENU) ? MENU_GetSysMenu( hwnd, 0 ) : 0;
+    wndPtr->hSysMenu       = (wndPtr->dwStyle & WS_SYSMENU) ? MENU_GetSysMenu( hwnd, -1 ) : 0;
 
     /*
      * Correct the window styles.






More information about the wine-patches mailing list