Hello, this patch was tested by Duane Clark and confirmed to fix a reported problem (I've added a test case for that bug). Many thanks to Duane for testing. This patch is still misses a proper MDICREATESTRUCT conversion for 16-bit windows since I have no 16-bit test apps. Changelog: Dmitry Timoshkov <dmitry@xxxxxxxxxxxxxxx> Merge the MDI and common window creation code. Change a way MDI children are managed in MDIClient. Add support for MDICREATESTRUCT A<->W conversions. Add support for WM_MDIREFRESHMENU. diff -u cvs/hq/wine/dlls/user/tests/win.c wine/dlls/user/tests/win.c --- cvs/hq/wine/dlls/user/tests/win.c 2004-01-16 17:47:26.000000000 +0800 +++ wine/dlls/user/tests/win.c 2004-01-16 22:38:48.000000000 +0800 @@ -696,34 +696,180 @@ static void test_MDI_create(HWND parent, { MDICREATESTRUCTA mdi_cs; HWND mdi_child; + static const WCHAR classW[] = {'M','D','I','_','c','h','i','l','d','_','C','l','a','s','s','_','1',0}; + static const WCHAR titleW[] = {'M','D','I',' ','c','h','i','l','d',0}; + BOOL isWin9x = FALSE; mdi_cs.szClass = "MDI_child_Class_1"; - mdi_cs.szTitle = "MDI child 1"; + mdi_cs.szTitle = "MDI child"; mdi_cs.hOwner = GetModuleHandle(0); - mdi_cs.x = 0; - mdi_cs.y = 0; + mdi_cs.x = CW_USEDEFAULT; + mdi_cs.y = CW_USEDEFAULT; mdi_cs.cx = CW_USEDEFAULT; mdi_cs.cy = CW_USEDEFAULT; - mdi_cs.style = WS_CAPTION | WS_CHILD /*| WS_VISIBLE*/; + mdi_cs.style = 0; mdi_cs.lParam = (LPARAM)mdi_lParam_test_message; mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs); - assert(mdi_child); + ok(mdi_child != 0, "MDI child creation failed\n"); DestroyWindow(mdi_child); - mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child 2", - WS_CAPTION | WS_CHILD /*| WS_VISIBLE*/, - 10, 10, CW_USEDEFAULT, CW_USEDEFAULT, + mdi_cs.style = 0x7fffffff; /* without WS_POPUP */ + mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs); + ok(mdi_child != 0, "MDI child creation failed\n"); + DestroyWindow(mdi_child); + + mdi_cs.style = 0xffffffff; /* with WS_POPUP */ + mdi_child = (HWND)SendMessageA(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs); + if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES) + { + ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n"); + DestroyWindow(mdi_child); + } + else + ok(mdi_child != 0, "MDI child creation failed\n"); + + /* test MDICREATESTRUCT A<->W mapping */ + /* MDICREATESTRUCTA and MDICREATESTRUCTW have the same layout */ + mdi_cs.style = 0; + mdi_cs.szClass = (LPCSTR)classW; + mdi_cs.szTitle = (LPCSTR)titleW; + SetLastError(0xdeadbeef); + mdi_child = (HWND)SendMessageW(mdi_client, WM_MDICREATE, 0, (LPARAM)&mdi_cs); + if (!mdi_child) + { + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + isWin9x = TRUE; + else + ok(mdi_child != 0, "MDI child creation failed\n"); + } + DestroyWindow(mdi_child); + + mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child", + 0, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + mdi_client, GetModuleHandle(0), + (LPARAM)mdi_lParam_test_message); + ok(mdi_child != 0, "MDI child creation failed\n"); + DestroyWindow(mdi_child); + + mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child", + 0x7fffffff, /* without WS_POPUP */ + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + mdi_client, GetModuleHandle(0), + (LPARAM)mdi_lParam_test_message); + ok(mdi_child != 0, "MDI child creation failed\n"); + DestroyWindow(mdi_child); + + mdi_child = CreateMDIWindowA("MDI_child_Class_1", "MDI child", + 0xffffffff, /* with WS_POPUP */ + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, GetModuleHandle(0), (LPARAM)mdi_lParam_test_message); - assert(mdi_child); + if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES) + { + ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n"); + DestroyWindow(mdi_child); + } + else + ok(mdi_child != 0, "MDI child creation failed\n"); + + /* test MDICREATESTRUCT A<->W mapping */ + SetLastError(0xdeadbeef); + mdi_child = CreateMDIWindowW(classW, titleW, + 0, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + mdi_client, GetModuleHandle(0), + (LPARAM)mdi_lParam_test_message); + if (!mdi_child) + { + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + isWin9x = TRUE; + else + ok(mdi_child != 0, "MDI child creation failed\n"); + } DestroyWindow(mdi_child); - mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child 3", - WS_CAPTION | WS_CHILD /*| WS_VISIBLE*/, - 20, 20, CW_USEDEFAULT, CW_USEDEFAULT, + mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child", + 0, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, mdi_client, 0, GetModuleHandle(0), (LPVOID)mdi_lParam_test_message); - assert(mdi_child); + ok(mdi_child != 0, "MDI child creation failed\n"); + DestroyWindow(mdi_child); + + mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child", + 0x7fffffff, /* without WS_POPUP */ + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + mdi_client, 0, GetModuleHandle(0), + (LPVOID)mdi_lParam_test_message); + ok(mdi_child != 0, "MDI child creation failed\n"); + DestroyWindow(mdi_child); + + mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_1", "MDI child", + 0xffffffff, /* with WS_POPUP */ + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + mdi_client, 0, GetModuleHandle(0), + (LPVOID)mdi_lParam_test_message); + if (GetWindowLongA(mdi_client, GWL_STYLE) & MDIS_ALLCHILDSTYLES) + { + ok(!mdi_child, "MDI child with WS_POPUP and with MDIS_ALLCHILDSTYLES should fail\n"); + DestroyWindow(mdi_child); + } + else + ok(mdi_child != 0, "MDI child creation failed\n"); + + /* test MDICREATESTRUCT A<->W mapping */ + SetLastError(0xdeadbeef); + mdi_child = CreateWindowExW(WS_EX_MDICHILD, classW, titleW, + 0, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + mdi_client, 0, GetModuleHandle(0), + (LPVOID)mdi_lParam_test_message); + if (!mdi_child) + { + if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + isWin9x = TRUE; + else + ok(mdi_child != 0, "MDI child creation failed\n"); + } + DestroyWindow(mdi_child); + + /* This test fails on Win9x */ + if (!isWin9x) + { + mdi_child = CreateWindowExA(WS_EX_MDICHILD, "MDI_child_Class_2", "MDI child", + WS_CHILD, + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + parent, 0, GetModuleHandle(0), + (LPVOID)mdi_lParam_test_message); + ok(!mdi_child, "WS_EX_MDICHILD with a not MDIClient parent should fail\n"); + } + + mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child", + WS_CHILD, /* without WS_POPUP */ + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + mdi_client, 0, GetModuleHandle(0), + (LPVOID)mdi_lParam_test_message); + ok(mdi_child != 0, "MDI child creation failed\n"); + DestroyWindow(mdi_child); + + mdi_child = CreateWindowExA(0, "MDI_child_Class_2", "MDI child", + WS_CHILD | WS_POPUP, /* with WS_POPUP */ + CW_USEDEFAULT, CW_USEDEFAULT, + CW_USEDEFAULT, CW_USEDEFAULT, + mdi_client, 0, GetModuleHandle(0), + (LPVOID)mdi_lParam_test_message); + ok(mdi_child != 0, "MDI child creation failed\n"); DestroyWindow(mdi_child); } @@ -731,16 +877,53 @@ static LRESULT WINAPI mdi_child_wnd_proc { switch (msg) { + case WM_NCCREATE: case WM_CREATE: { CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam; MDICREATESTRUCTA *mdi_cs = (MDICREATESTRUCTA *)cs->lpCreateParams; -todo_wine /* apparently Windows has a common code for MDI and other windows */ -{ ok(cs->dwExStyle & WS_EX_MDICHILD, "WS_EX_MDICHILD should be set\n"); -} ok(mdi_cs->lParam == (LPARAM)mdi_lParam_test_message, "wrong mdi_cs->lParam\n"); + + ok(!lstrcmpA(cs->lpszClass, "MDI_child_Class_1"), "wrong class name\n"); + ok(!lstrcmpA(cs->lpszClass, mdi_cs->szClass), "class name does not match\n"); + ok(!lstrcmpA(cs->lpszName, "MDI child"), "wrong title\n"); + ok(!lstrcmpA(cs->lpszName, mdi_cs->szTitle), "title does not match\n"); + ok(cs->hInstance == mdi_cs->hOwner, "%p != %p\n", cs->hInstance, mdi_cs->hOwner); + + /* MDICREATESTRUCT should have original values */ + ok(mdi_cs->style == 0 || mdi_cs->style == 0x7fffffff || mdi_cs->style == 0xffffffff, + "mdi_cs->style does not match (%08lx)\n", mdi_cs->style); + ok(mdi_cs->x == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->x); + ok(mdi_cs->y == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->y); + ok(mdi_cs->cx == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->cx); + ok(mdi_cs->cy == CW_USEDEFAULT, "%d != CW_USEDEFAULT\n", mdi_cs->cy); + + /* CREATESTRUCT should have fixed values */ + ok(cs->x != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->x); + ok(cs->y != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->y); + + /* cx/cy == CW_USEDEFAULT are translated to NOT zero values */ + ok(cs->cx != CW_USEDEFAULT && cs->cx != 0, "%d == CW_USEDEFAULT\n", cs->cx); + ok(cs->cy != CW_USEDEFAULT && cs->cy != 0, "%d == CW_USEDEFAULT\n", cs->cy); + + ok(!(cs->style & WS_POPUP), "WS_POPUP is not allowed\n"); + + if (GetWindowLongA(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES) + { + ok(cs->style == (mdi_cs->style | WS_CHILD | WS_CLIPSIBLINGS), + "cs->style does not match (%08lx)\n", cs->style); + } + else + { + DWORD style = mdi_cs->style; + style &= ~WS_POPUP; + style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION | + WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; + ok(cs->style == style, + "cs->style does not match (%08lx)\n", cs->style); + } break; } } @@ -751,12 +934,26 @@ static LRESULT WINAPI mdi_child_wnd_proc { switch (msg) { + case WM_NCCREATE: case WM_CREATE: { CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam; ok(!(cs->dwExStyle & WS_EX_MDICHILD), "WS_EX_MDICHILD should not be set\n"); ok(cs->lpCreateParams == mdi_lParam_test_message, "wrong cs->lpCreateParams\n"); + + ok(!lstrcmpA(cs->lpszClass, "MDI_child_Class_2"), "wrong class name\n"); + ok(!lstrcmpA(cs->lpszName, "MDI child"), "wrong title\n"); + + /* CREATESTRUCT should have fixed values */ + /* For some reason Win9x doesn't translate cs->x from CW_USEDEFAULT, + while NT does. */ + /*ok(cs->x != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->x);*/ + ok(cs->y != CW_USEDEFAULT, "%d == CW_USEDEFAULT\n", cs->y); + + /* cx/cy == CW_USEDEFAULT are translated to 0 */ + ok(cs->cx == 0, "%d != 0\n", cs->cx); + ok(cs->cy == 0, "%d != 0\n", cs->cy); break; } } @@ -779,15 +976,29 @@ static LRESULT WINAPI mdi_main_wnd_procA client_cs.hWindowMenu = 0; client_cs.idFirstChild = 1; + /* MDIClient without MDIS_ALLCHILDSTYLES */ mdi_client = CreateWindowExA(0, "mdiclient", NULL, - WS_CHILD | WS_CLIPCHILDREN /*| WS_VISIBLE*/, + WS_CHILD /*| WS_VISIBLE*/, + /* tests depend on a not zero MDIClient size */ 0, 0, rc.right, rc.bottom, hwnd, 0, GetModuleHandle(0), (LPVOID)&client_cs); assert(mdi_client); + test_MDI_create(hwnd, mdi_client); + DestroyWindow(mdi_client); + /* MDIClient with MDIS_ALLCHILDSTYLES */ + mdi_client = CreateWindowExA(0, "mdiclient", + NULL, + WS_CHILD | MDIS_ALLCHILDSTYLES /*| WS_VISIBLE*/, + /* tests depend on a not zero MDIClient size */ + 0, 0, rc.right, rc.bottom, + hwnd, 0, GetModuleHandle(0), + (LPVOID)&client_cs); + assert(mdi_client); test_MDI_create(hwnd, mdi_client); + DestroyWindow(mdi_client); break; } @@ -890,20 +1101,23 @@ static void test_icons(void) res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); ok( res == 0, "wrong small icon %p/0\n", res ); - res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); - ok( res != 0, "wrong small icon %p\n", res ); + /* this test is XP specific */ + /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); + ok( res != 0, "wrong small icon %p\n", res );*/ res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)icon ); ok( res == 0, "wrong previous small icon %p/0\n", res ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); ok( res == icon, "wrong small icon after set %p/%p\n", res, icon ); - res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); - ok( res == icon, "wrong small icon after set %p/%p\n", res, icon ); + /* this test is XP specific */ + /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); + ok( res == icon, "wrong small icon after set %p/%p\n", res, icon );*/ res = (HICON)SendMessageA( hwnd, WM_SETICON, ICON_SMALL, (LPARAM)small_icon ); ok( res == icon, "wrong previous small icon %p/%p\n", res, icon ); res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL, 0 ); ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon ); - res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); - ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon ); + /* this test is XP specific */ + /*res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_SMALL2, 0 ); + ok( res == small_icon, "wrong small icon after set %p/%p\n", res, small_icon );*/ /* make sure the big icon hasn't changed */ res = (HICON)SendMessageA( hwnd, WM_GETICON, ICON_BIG, 0 ); diff -u cvs/hq/wine/include/win.h wine/include/win.h --- cvs/hq/wine/include/win.h 2004-01-01 15:33:56.000000000 +0800 +++ wine/include/win.h 2004-01-16 17:50:18.000000000 +0800 @@ -86,6 +86,7 @@ typedef struct #define WIN_INTERNAL_PAINT 0x0010 /* Internal WM_PAINT message pending */ #define WIN_NEED_SIZE 0x0040 /* Internal WM_SIZE is needed */ #define WIN_NCACTIVATED 0x0080 /* last WM_NCACTIVATE was positive */ +#define WIN_ISMDICLIENT 0x0100 /* Window is an MDIClient */ #define WIN_ISDIALOG 0x0200 /* Window is a dialog */ #define WIN_ISWIN32 0x0400 /* Understands Win32 messages */ #define WIN_NEEDS_SHOW_OWNEDPOPUP 0x0800 /* WM_SHOWWINDOW:SC_SHOW must be sent in the next ShowOwnedPopup call */ @@ -114,6 +115,7 @@ extern BOOL WIN_IsWindowDrawable( HWND h extern HWND *WIN_ListParents( HWND hwnd ); extern HWND *WIN_ListChildren( HWND hwnd ); extern BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly ); +extern void MDI_CalcDefaultChildPos( HWND hwndClient, INT total, LPPOINT lpPos, INT delta ); inline static HWND WIN_GetFullHandle( HWND hwnd ) { diff -u cvs/hq/wine/windows/mdi.c wine/windows/mdi.c --- cvs/hq/wine/windows/mdi.c 2004-01-05 16:06:12.000000000 +0800 +++ wine/windows/mdi.c 2004-01-17 00:10:41.000000000 +0800 @@ -102,13 +102,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(mdi); -#define MDI_MAXLISTLENGTH 0x40 #define MDI_MAXTITLELENGTH 0xa1 -#define MDI_NOFRAMEREPAINT 0 -#define MDI_REPAINTFRAMENOW 1 -#define MDI_REPAINTFRAME 2 - #define WM_MDICALCCHILDSCROLL 0x10ac /* this is exactly what Windows uses */ /* "More Windows..." definitions */ @@ -121,10 +116,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(mdi); typedef struct { + CRITICAL_SECTION lock; UINT nActiveChildren; - HWND hwndChildMaximized; HWND hwndActiveChild; + HWND *child; /* array of tracked children */ + HMENU hFrameMenu; HMENU hWindowMenu; + UINT add_pos; /* original number of items in the window menu */ UINT idFirstChild; LPWSTR frameTitle; UINT nTotalCreated; @@ -139,9 +137,9 @@ static void MDI_UpdateFrameText( HWND, H static BOOL MDI_AugmentFrameMenu( HWND, HWND ); static BOOL MDI_RestoreFrameMenu( HWND, HWND ); static LONG MDI_ChildActivate( HWND, HWND ); +static LRESULT MDI_RefreshMenu(MDICLIENTINFO *); static HWND MDI_MoreWindowsDialog(HWND); -static void MDI_SwapMenuItems(HWND, UINT, UINT); static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ); static LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ); @@ -149,20 +147,16 @@ static LRESULT WINAPI MDIClientWndProcW( * * MDI_GetChildByID */ -static HWND MDI_GetChildByID(HWND hwnd, UINT id) +static HWND MDI_GetChildByID(HWND hwnd, UINT id, MDICLIENTINFO *ci) { - HWND ret; - HWND *win_array; int i; - if (!(win_array = WIN_ListChildren( hwnd ))) return 0; - for (i = 0; win_array[i]; i++) + for (i = 0; ci->nActiveChildren; i++) { - if (GetWindowLongA( win_array[i], GWL_ID ) == id) break; + if (GetWindowLongW( ci->child[i], GWL_ID ) == id) + return ci->child[i]; } - ret = win_array[i]; - HeapFree( GetProcessHeap(), 0, win_array ); - return ret; + return 0; } static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc) @@ -210,83 +204,6 @@ static MDICLIENTINFO *get_client_info( H } /********************************************************************** - * MDI_MenuModifyItem - */ -static void MDI_MenuModifyItem( HWND client, HWND hWndChild ) -{ - MDICLIENTINFO *clientInfo = get_client_info( client ); - WCHAR buffer[128]; - UINT n, id; - - if (!clientInfo || !clientInfo->hWindowMenu) return; - - id = GetWindowLongA( hWndChild, GWL_ID ); - if (id >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT) return; - buffer[0] = '&'; - buffer[1] = '1' + id - clientInfo->idFirstChild; - buffer[2] = ' '; - GetWindowTextW( hWndChild, buffer + 3, sizeof(buffer)/sizeof(WCHAR) - 3 ); - - n = GetMenuState(clientInfo->hWindowMenu, id, MF_BYCOMMAND); - ModifyMenuW(clientInfo->hWindowMenu, id, MF_BYCOMMAND | MF_STRING, id, buffer ); - CheckMenuItem(clientInfo->hWindowMenu, id, n & MF_CHECKED); -} - -/********************************************************************** - * MDI_MenuDeleteItem - */ -static BOOL MDI_MenuDeleteItem( HWND client, HWND hWndChild ) -{ - WCHAR buffer[128]; - static const WCHAR format[] = {'&','%','d',' ',0}; - MDICLIENTINFO *clientInfo = get_client_info( client ); - UINT index = 0,id,n; - - if( !clientInfo->nActiveChildren || !clientInfo->hWindowMenu ) - return FALSE; - - id = GetWindowLongA( hWndChild, GWL_ID ); - DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND); - - /* walk the rest of MDI children to prevent gaps in the id - * sequence and in the menu child list */ - - for( index = id+1; index <= clientInfo->nActiveChildren + - clientInfo->idFirstChild; index++ ) - { - HWND hwnd = MDI_GetChildByID(client,index); - if (!hwnd) - { - TRACE("no window for id=%i\n",index); - continue; - } - - /* set correct id */ - SetWindowLongW( hwnd, GWL_ID, GetWindowLongW( hwnd, GWL_ID ) - 1 ); - - n = wsprintfW(buffer, format ,index - clientInfo->idFirstChild); - GetWindowTextW( hwnd, buffer + n, sizeof(buffer)/sizeof(WCHAR) - n ); - - /* change menu if the current child is to be shown in the - * "Windows" menu - */ - if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT) - ModifyMenuW(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING, - index - 1 , buffer ); - } - - /* We must restore the "More Windows..." option if there are enough children - */ - if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT) - { - WCHAR szTmp[50]; - LoadStringW(GetModuleHandleA("USER32"), IDS_MDI_MOREWINDOWS, szTmp, sizeof(szTmp)/sizeof(szTmp[0])); - AppendMenuW(clientInfo->hWindowMenu, MF_STRING, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp); - } - return TRUE; -} - -/********************************************************************** * MDI_GetWindow * * returns "activateable" child different from the current or zero @@ -332,21 +249,34 @@ static HWND MDI_GetWindow(MDICLIENTINFO * * It seems that the default height is about 2/3 of the client rect */ -static void MDI_CalcDefaultChildPos( HWND hwnd, WORD n, LPPOINT lpPos, INT delta) +void MDI_CalcDefaultChildPos( HWND hwndClient, INT total, LPPOINT lpPos, INT delta ) { INT nstagger; RECT rect; INT spacing = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME) - 1; - GetClientRect( hwnd, &rect ); + if (total < 0) + { + MDICLIENTINFO *ci = get_client_info(hwndClient); + if (ci) + { + EnterCriticalSection(&ci->lock); + total = ci->nTotalCreated; + LeaveCriticalSection(&ci->lock); + } + else + total = 0; + } + + GetClientRect( hwndClient, &rect ); if( rect.bottom - rect.top - delta >= spacing ) rect.bottom -= delta; nstagger = (rect.bottom - rect.top)/(3 * spacing); lpPos[1].x = (rect.right - rect.left - nstagger * spacing); lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing); - lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1)); + lpPos[0].x = lpPos[0].y = spacing * (total%(nstagger+1)); } /********************************************************************** @@ -357,7 +287,6 @@ static LRESULT MDISetMenu( HWND hwnd, HM { MDICLIENTINFO *ci; HWND hwndFrame = GetParent(hwnd); - HMENU oldFrameMenu = GetMenu(hwndFrame); TRACE("%p %p %p\n", hwnd, hmenuFrame, hmenuWindow); @@ -375,8 +304,10 @@ static LRESULT MDISetMenu( HWND hwnd, HM if (!(ci = get_client_info( hwnd ))) return 0; - if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu ) - MDI_RestoreFrameMenu( GetParent(hwnd), ci->hwndChildMaximized ); + EnterCriticalSection(&ci->lock); + + if( IsZoomed(ci->hwndActiveChild) && hmenuFrame && hmenuFrame!= ci->hFrameMenu ) + MDI_RestoreFrameMenu( hwndFrame, ci->hwndActiveChild ); if( hmenuWindow && hmenuWindow != ci->hWindowMenu ) { @@ -385,65 +316,44 @@ static LRESULT MDISetMenu( HWND hwnd, HM /* Agent newsreader calls this function with ci->hWindowMenu == NULL */ if( ci->hWindowMenu && ci->nActiveChildren ) { - INT j; - LPWSTR buffer = NULL; - MENUITEMINFOW mii; - INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */ - INT i = GetMenuItemCount(ci->hWindowMenu) - 1; - INT pos = GetMenuItemCount(hmenuWindow) + 1; + UINT nActiveChildren_old = ci->nActiveChildren; - AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL); - - if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT) - nbWindowsMenuItems = ci->nActiveChildren; - else - nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1; - - j = i - nbWindowsMenuItems + 1; - - for( ; i >= j ; i-- ) - { - memset(&mii, 0, sizeof(mii)); - mii.cbSize = sizeof(mii); - mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE - | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP; - - GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii); - if(mii.cch) { /* Menu is MFT_STRING */ - mii.cch++; /* add room for '\0' */ - buffer = HeapAlloc(GetProcessHeap(), 0, - mii.cch * sizeof(WCHAR)); - mii.dwTypeData = buffer; - GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii); - } - DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION); - InsertMenuItemW(hmenuWindow, pos, TRUE, &mii); - if(buffer) { - HeapFree(GetProcessHeap(), 0, buffer); - buffer = NULL; - } - } - /* remove separator */ - DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION); + /* Remove all items from old Window menu */ + ci->nActiveChildren = 0; + MDI_RefreshMenu(ci); + + ci->add_pos = GetMenuItemCount(hmenuWindow); + ci->hWindowMenu = hmenuWindow; + + /* Add items to the new Window menu */ + ci->nActiveChildren = nActiveChildren_old; + MDI_RefreshMenu(ci); } + else + ci->add_pos = GetMenuItemCount(hmenuWindow); + ci->hWindowMenu = hmenuWindow; } if (hmenuFrame) { SetMenu(hwndFrame, hmenuFrame); - if( hmenuFrame!=oldFrameMenu ) + if( hmenuFrame != ci->hFrameMenu ) { - if( ci->hwndChildMaximized ) - MDI_AugmentFrameMenu( GetParent(hwnd), ci->hwndChildMaximized ); + HMENU oldFrameMenu = ci->hFrameMenu; + + ci->hFrameMenu = hmenuFrame; + if( IsZoomed(ci->hwndActiveChild) ) + MDI_AugmentFrameMenu( hwndFrame, ci->hwndActiveChild ); + + LeaveCriticalSection(&ci->lock); return (LRESULT)oldFrameMenu; } } else { - HMENU menu = GetMenu( GetParent(hwnd) ); - INT nItems = GetMenuItemCount(menu) - 1; - UINT iId = GetMenuItemID(menu,nItems) ; + INT nItems = GetMenuItemCount(ci->hFrameMenu) - 1; + UINT iId = GetMenuItemID(ci->hFrameMenu, nItems); if( !(iId == SC_RESTORE || iId == SC_CLOSE) ) { @@ -453,185 +363,79 @@ static LRESULT MDISetMenu( HWND hwnd, HM * that the "if" to this "else" wouldn't catch the need to * augment the frame menu. */ - if( ci->hwndChildMaximized ) - MDI_AugmentFrameMenu( GetParent(hwnd), ci->hwndChildMaximized ); + if( IsZoomed(ci->hwndActiveChild) ) + MDI_AugmentFrameMenu( hwndFrame, ci->hwndActiveChild ); } } + + LeaveCriticalSection(&ci->lock); return 0; } /********************************************************************** * MDIRefreshMenu */ -static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame, - HMENU hmenuWindow) -{ - HWND hwndFrame = GetParent(hwnd); - HMENU oldFrameMenu = GetMenu(hwndFrame); - - TRACE("%p %p %p\n", hwnd, hmenuFrame, hmenuWindow); - - FIXME("partially function stub\n"); - - return (LRESULT)oldFrameMenu; -} - - -/* ------------------ MDI child window functions ---------------------- */ - - -/********************************************************************** - * MDICreateChild - */ -static HWND MDICreateChild( HWND parent, MDICLIENTINFO *ci, - LPMDICREATESTRUCTA cs, BOOL unicode ) +static LRESULT MDI_RefreshMenu(MDICLIENTINFO *ci) { - POINT pos[2]; - DWORD style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS); - HWND hwnd, hwndMax = 0; - UINT wIDmenu = ci->idFirstChild + ci->nActiveChildren; - WND *wndParent; - static const WCHAR lpstrDef[] = {'j','u','n','k','!',0}; + HMENU hFrameMenu; + UINT i, count, visible; + WCHAR buf[MDI_MAXTITLELENGTH]; - TRACE("origin %i,%i - dim %i,%i, style %08lx\n", - cs->x, cs->y, cs->cx, cs->cy, cs->style); - /* calculate placement */ - MDI_CalcDefaultChildPos(parent, ci->nTotalCreated++, pos, 0); + EnterCriticalSection(&ci->lock); - if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16 || !cs->cx) cs->cx = pos[1].x; - if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16 || !cs->cy) cs->cy = pos[1].y; + TRACE("children %u, window menu %p\n", ci->nActiveChildren, ci->hWindowMenu); - if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) + if (!ci->hWindowMenu) { - cs->x = pos[0].x; - cs->y = pos[0].y; + LeaveCriticalSection(&ci->lock); + return 0; } - /* restore current maximized child */ - if( (style & WS_VISIBLE) && ci->hwndChildMaximized ) + count = GetMenuItemCount(ci->hWindowMenu); + for (i = ci->add_pos; i < count; i++) + RemoveMenu(ci->hWindowMenu, ci->add_pos, MF_BYPOSITION); + + visible = 0; + for (i = 0; i < ci->nActiveChildren; i++) { - TRACE("Restoring current maximized child %p\n", ci->hwndChildMaximized); - if( style & WS_MAXIMIZE ) - SendMessageW(parent, WM_SETREDRAW, FALSE, 0L); - hwndMax = ci->hwndChildMaximized; - ShowWindow( hwndMax, SW_SHOWNOACTIVATE ); - if( style & WS_MAXIMIZE ) - SendMessageW(parent, WM_SETREDRAW, TRUE, 0L); - } + UINT id = ci->idFirstChild + i; - if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT) - /* this menu is needed to set a check mark in MDI_ChildActivate */ - if (ci->hWindowMenu != 0) - AppendMenuW(ci->hWindowMenu, MF_STRING, wIDmenu, lpstrDef); + if (visible == MDI_MOREWINDOWSLIMIT) + { + LoadStringW(GetModuleHandleA("USER32"), IDS_MDI_MOREWINDOWS, buf, sizeof(buf)/sizeof(WCHAR)); + AppendMenuW(ci->hWindowMenu, MF_STRING, id, buf); + break; + } - ci->nActiveChildren++; + if (IsWindowVisible(ci->child[i])) + { + if (!visible) + AppendMenuW(ci->hWindowMenu, MF_SEPARATOR, -1, NULL); - /* fix window style */ - wndParent = WIN_FindWndPtr( parent ); - if( !(wndParent->dwStyle & MDIS_ALLCHILDSTYLES) ) - { - TRACE("MDIS_ALLCHILDSTYLES is missing, fixing window style\n"); - style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE | - WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL ); - style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW); - } + visible++; - if( wndParent->flags & WIN_ISWIN32 ) - { - WIN_ReleaseWndPtr( wndParent ); - /* FIXME: CreateWindowEx must be called with WS_EX_MDICHILD set, but - * it requires to move MDI specific child creation to CreateWindowEx - * and do child tracking in MDICLIENT using WM_PARENTNOTIFY. - */ - if(unicode) - { - MDICREATESTRUCTW *csW = (MDICREATESTRUCTW *)cs; - hwnd = CreateWindowExW( 0, csW->szClass, csW->szTitle, style, - csW->x, csW->y, csW->cx, csW->cy, parent, - (HMENU)wIDmenu, csW->hOwner, csW ); - } - else - hwnd = CreateWindowExA( 0, cs->szClass, cs->szTitle, style, - cs->x, cs->y, cs->cx, cs->cy, parent, - (HMENU)wIDmenu, cs->hOwner, cs ); - } - else - { - MDICREATESTRUCT16 cs16; - SEGPTR title, cls, seg_cs16; + SetWindowLongW(ci->child[i], GWL_ID, id); - WIN_ReleaseWndPtr( wndParent ); - STRUCT32_MDICREATESTRUCT32Ato16( cs, &cs16 ); - cs16.szTitle = title = MapLS( cs->szTitle ); - cs16.szClass = cls = MapLS( cs->szClass ); - seg_cs16 = MapLS( &cs16 ); - hwnd = WIN_Handle32( CreateWindowEx16( 0, cs->szClass, cs->szTitle, style, - cs16.x, cs16.y, cs16.cx, cs16.cy, - HWND_16(parent), (HMENU16)wIDmenu, - cs16.hOwner, (LPVOID)seg_cs16 )); - UnMapLS( seg_cs16 ); - UnMapLS( title ); - UnMapLS( cls ); - } - - /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */ - - if (hwnd) - { - /* All MDI child windows have the WS_EX_MDICHILD style */ - SetWindowLongW( hwnd, GWL_EXSTYLE, GetWindowLongW( hwnd, GWL_EXSTYLE ) | WS_EX_MDICHILD ); - - /* If we have more than 9 windows, we must insert the new one at the - * 9th position in order to see it in the "Windows" menu - */ - if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT) - MDI_SwapMenuItems( parent, GetWindowLongW( hwnd, GWL_ID ), - ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1); - - MDI_MenuModifyItem(parent, hwnd); - - /* Have we hit the "More Windows..." limit? If so, we must - * add a "More Windows..." option - */ - if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1) - { - WCHAR szTmp[50]; - LoadStringW(GetModuleHandleA("USER32"), IDS_MDI_MOREWINDOWS, szTmp, sizeof(szTmp)/sizeof(szTmp[0])); - - ModifyMenuW(ci->hWindowMenu, - ci->idFirstChild + MDI_MOREWINDOWSLIMIT, - MF_BYCOMMAND | MF_STRING, - ci->idFirstChild + MDI_MOREWINDOWSLIMIT, - szTmp); - } + buf[0] = '&'; + buf[1] = '0' + visible; + buf[2] = ' '; + InternalGetWindowText(ci->child[i], buf + 3, sizeof(buf)/sizeof(WCHAR) - 3); + AppendMenuW(ci->hWindowMenu, MF_STRING, id, buf); - if( IsIconic(hwnd) && ci->hwndActiveChild ) - { - TRACE("Minimizing created MDI child %p\n", hwnd); - ShowWindow( hwnd, SW_SHOWMINNOACTIVE ); - } - else - { - /* WS_VISIBLE is clear if a) the MDI client has - * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the - * MDICreateStruct. If so the created window is not shown nor - * activated. - */ - if (IsWindowVisible(hwnd)) ShowWindow(hwnd, SW_SHOW); - } - TRACE("created child - %p\n",hwnd); - } - else - { - ci->nActiveChildren--; - DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND); - if( IsWindow(hwndMax) ) - ShowWindow(hwndMax, SW_SHOWMAXIMIZED); + if (ci->child[i] == ci->hwndActiveChild) + CheckMenuItem(ci->hWindowMenu, id, MF_CHECKED); + } } - return hwnd; + hFrameMenu = ci->hFrameMenu; + LeaveCriticalSection(&ci->lock); + + return (LRESULT)hFrameMenu; } + +/* ------------------ MDI child window functions ---------------------- */ + /********************************************************************** * MDI_ChildGetMinMaxInfo * @@ -669,14 +473,17 @@ static void MDI_SwitchActiveChild( HWND HWND hwndPrev = 0; MDICLIENTINFO *ci = get_client_info( clientHwnd ); + EnterCriticalSection(&ci->lock); + hwndTo = MDI_GetWindow(ci, childHwnd, bNextWindow, 0); + hwndPrev = ci->hwndActiveChild; + + LeaveCriticalSection(&ci->lock); TRACE("from %p, to %p\n",childHwnd,hwndTo); if ( !hwndTo ) return; /* no window to switch to */ - hwndPrev = ci->hwndActiveChild; - if ( hwndTo != hwndPrev ) { SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0, @@ -695,6 +502,10 @@ static void MDI_SwitchActiveChild( HWND static LRESULT MDIDestroyChild( HWND parent, MDICLIENTINFO *ci, HWND child, BOOL flagDestroy ) { + UINT i; + + EnterCriticalSection(&ci->lock); + if( child == ci->hwndActiveChild ) { MDI_SwitchActiveChild(parent, child, TRUE); @@ -702,11 +513,10 @@ static LRESULT MDIDestroyChild( HWND par if( child == ci->hwndActiveChild ) { ShowWindow( child, SW_HIDE); - if( child == ci->hwndChildMaximized ) + if( child == ci->hwndActiveChild && IsZoomed(ci->hwndActiveChild) ) { HWND frame = GetParent(parent); MDI_RestoreFrameMenu( frame, child ); - ci->hwndChildMaximized = 0; MDI_UpdateFrameText( frame, parent, TRUE, NULL); } @@ -714,7 +524,18 @@ static LRESULT MDIDestroyChild( HWND par } } - MDI_MenuDeleteItem(parent, child); + for (i = 0; i < ci->nActiveChildren; i++) + { + if (ci->child[i] == child) + { + HWND *new_child = HeapAlloc(GetProcessHeap(), 0, (ci->nActiveChildren - 1) * sizeof(HWND)); + memcpy(new_child, ci->child, i * sizeof(HWND)); + if (i + 1 < ci->nActiveChildren) + memcpy(new_child + i, ci->child + i + 1, (ci->nActiveChildren - i - 1) * sizeof(HWND)); + HeapFree(GetProcessHeap(), 0, ci->child); + ci->child = new_child; + } + } ci->nActiveChildren--; @@ -725,6 +546,9 @@ static LRESULT MDIDestroyChild( HWND par MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1); DestroyWindow(child); } + + LeaveCriticalSection(&ci->lock); + return 0; } @@ -736,19 +560,27 @@ static LRESULT MDIDestroyChild( HWND par */ static LONG MDI_ChildActivate( HWND client, HWND child ) { - MDICLIENTINFO *clientInfo = get_client_info( client ); - HWND prevActiveWnd = clientInfo->hwndActiveChild; + MDICLIENTINFO *clientInfo; + HWND prevActiveWnd; BOOL isActiveFrameWnd; if (child && (!IsWindowEnabled( child ))) return 0; + clientInfo = get_client_info( client ); + EnterCriticalSection(&clientInfo->lock); + /* Don't activate if it is already active. Might happen since ShowWindow DOES activate MDI children */ - if (clientInfo->hwndActiveChild == child) return 0; + if (clientInfo->hwndActiveChild == child) + { + LeaveCriticalSection(&clientInfo->lock); + return 0; + } TRACE("%p\n", child); isActiveFrameWnd = (GetActiveWindow() == GetParent(client)); + prevActiveWnd = clientInfo->hwndActiveChild; /* deactivate prev. active child */ if(prevActiveWnd) @@ -771,17 +603,21 @@ static LONG MDI_ChildActivate( HWND clie } /* set appearance */ - if (clientInfo->hwndChildMaximized && clientInfo->hwndChildMaximized != child) + if (IsZoomed(clientInfo->hwndActiveChild) && clientInfo->hwndActiveChild != child) { INT cmd = SW_SHOWNORMAL; if( child ) { - UINT state = GetMenuState(GetSystemMenu(child, FALSE), SC_MAXIMIZE, MF_BYCOMMAND); - if (state != 0xFFFFFFFF && (state & (MF_DISABLED | MF_GRAYED))) - SendMessageW(clientInfo->hwndChildMaximized, WM_SYSCOMMAND, SC_RESTORE, 0); - else + HMENU hSysMenu = GetSystemMenu(child, FALSE); + UINT state = 0; + if (hSysMenu) + state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND); + if (state != 0xFFFFFFFF && !(state & (MF_DISABLED | MF_GRAYED))) + { + SendMessageW(clientInfo->hwndActiveChild, WM_SYSCOMMAND, SC_RESTORE, 0); cmd = SW_SHOWMAXIMIZED; + } clientInfo->hwndActiveChild = child; } @@ -791,6 +627,9 @@ static LONG MDI_ChildActivate( HWND clie clientInfo->hwndActiveChild = child; + MDI_RefreshMenu(clientInfo); + LeaveCriticalSection(&clientInfo->lock); + /* check if we have any children left */ if( !child ) { @@ -799,21 +638,6 @@ static LONG MDI_ChildActivate( HWND clie return 0; } - /* check menu item */ - if( clientInfo->hWindowMenu ) - { - UINT id = GetWindowLongA( child, GWL_ID ); - /* The window to be activated must be displayed in the "Windows" menu */ - if (id >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT) - { - MDI_SwapMenuItems( GetParent(child), - id, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1); - id = clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1; - MDI_MenuModifyItem( GetParent(child), child ); - } - - CheckMenuItem(clientInfo->hWindowMenu, id, MF_CHECKED); - } /* bring active child to the top */ SetWindowPos( child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); @@ -874,9 +698,8 @@ static LONG MDICascade( HWND client, MDI BOOL has_icons = FALSE; int i, total; - if (ci->hwndChildMaximized) - SendMessageA( client, WM_MDIRESTORE, - (WPARAM)ci->hwndChildMaximized, 0); + if (IsZoomed(ci->hwndActiveChild)) + SendMessageA(client, WM_MDIRESTORE, (WPARAM)ci->hwndActiveChild, 0); if (ci->nActiveChildren == 0) return 0; @@ -928,8 +751,8 @@ static void MDITile( HWND client, MDICLI int i, total; BOOL has_icons = FALSE; - if (ci->hwndChildMaximized) - SendMessageA( client, WM_MDIRESTORE, (WPARAM)ci->hwndChildMaximized, 0); + if (IsZoomed(ci->hwndActiveChild)) + SendMessageA(client, WM_MDIRESTORE, (WPARAM)ci->hwndActiveChild, 0); if (ci->nActiveChildren == 0) return; @@ -1034,6 +857,13 @@ static BOOL MDI_AugmentFrameMenu( HWND f AppendMenuA(menu,MF_HELP | MF_BITMAP, SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE ); + /* The close button is only present in Win 95 look */ + if(TWEAK_WineLook > WIN31_LOOK) + { + AppendMenuA(menu,MF_HELP | MF_BITMAP, + SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE ); + } + /* In Win 95 look, the system menu is replaced by the child icon */ if(TWEAK_WineLook > WIN31_LOOK) @@ -1078,13 +908,6 @@ static BOOL MDI_AugmentFrameMenu( HWND f return 0; } - /* The close button is only present in Win 95 look */ - if(TWEAK_WineLook > WIN31_LOOK) - { - AppendMenuA(menu,MF_HELP | MF_BITMAP, - SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE ); - } - EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED); @@ -1166,6 +989,8 @@ static void MDI_UpdateFrameText( HWND fr if (!ci) return; + EnterCriticalSection(&ci->lock); + if (!lpTitle && !ci->frameTitle) /* first time around, get title from the frame window */ { GetWindowTextW( frame, lpBuffer, sizeof(lpBuffer)/sizeof(WCHAR) ); @@ -1182,7 +1007,7 @@ static void MDI_UpdateFrameText( HWND fr if (ci->frameTitle) { - if (ci->hwndChildMaximized) + if (IsZoomed(ci->hwndActiveChild)) { /* combine frame title and child title if possible */ @@ -1195,7 +1020,7 @@ static void MDI_UpdateFrameText( HWND fr if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH ) { strcatW( lpBuffer, lpBracket ); - if (GetWindowTextW( ci->hwndChildMaximized, lpBuffer + i_frame_text_length + 4, + if (GetWindowTextW( ci->hwndActiveChild, lpBuffer + i_frame_text_length + 4, MDI_MAXTITLELENGTH - i_frame_text_length - 5 )) strcatW( lpBuffer, lpBracket2 ); else @@ -1210,8 +1035,10 @@ static void MDI_UpdateFrameText( HWND fr else lpBuffer[0] = '\0'; + LeaveCriticalSection(&ci->lock); + DefWindowProcW( frame, WM_SETTEXT, 0, (LPARAM)lpBuffer ); - if( repaint == MDI_REPAINTFRAME) + if( repaint ) SetWindowPos( frame, 0,0,0,0,0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER ); } @@ -1228,27 +1055,29 @@ static LRESULT MDIClientWndProc_common( { MDICLIENTINFO *ci; + TRACE("%p %04x %08x %08lx\n", hwnd, message, wParam, lParam); + if (!(ci = get_client_info( hwnd ))) return 0; switch (message) { case WM_CREATE: { - RECT rect; /* Since we are using only cs->lpCreateParams, we can safely * cast to LPCREATESTRUCTA here */ LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam; WND *wndPtr = WIN_GetPtr( hwnd ); + wndPtr->flags |= WIN_ISMDICLIENT; + /* Translation layer doesn't know what's in the cs->lpCreateParams * so we have to keep track of what environment we're in. */ if( wndPtr->flags & WIN_ISWIN32 ) { -#define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams) + LPCLIENTCREATESTRUCT ccs = cs->lpCreateParams; ci->hWindowMenu = ccs->hWindowMenu; ci->idFirstChild = ccs->idFirstChild; -#undef ccs } else { @@ -1258,62 +1087,84 @@ static LRESULT MDIClientWndProc_common( } WIN_ReleasePtr( wndPtr ); - ci->hwndChildMaximized = 0; + InitializeCriticalSection(&ci->lock); + ci->child = NULL; ci->nActiveChildren = 0; ci->nTotalCreated = 0; ci->frameTitle = NULL; ci->mdiFlags = 0; - SetWindowLongW( hwnd, GWL_STYLE, GetWindowLongW(hwnd,GWL_STYLE) | WS_CLIPCHILDREN ); + ci->hFrameMenu = GetMenu(cs->hwndParent); + ci->add_pos = GetMenuItemCount(ci->hWindowMenu); if (!hBmpClose) hBmpClose = CreateMDIMenuBitmap(); - if (ci->hWindowMenu != 0) - AppendMenuW( ci->hWindowMenu, MF_SEPARATOR, 0, NULL ); - - GetClientRect( GetParent(hwnd), &rect); - MoveWindow( hwnd, 0, 0, rect.right, rect.bottom, FALSE ); - - MDI_UpdateFrameText( GetParent(hwnd), hwnd, MDI_NOFRAMEREPAINT, NULL); - TRACE("Client created - hwnd = %p, idFirst = %u\n", hwnd, ci->idFirstChild ); return 0; } case WM_DESTROY: { - INT nItems; - if( ci->hwndChildMaximized ) - MDI_RestoreFrameMenu( GetParent(hwnd), ci->hwndChildMaximized); - if((ci->hWindowMenu != 0) && - (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0) - { - ci->idFirstChild = nItems - 1; - ci->nActiveChildren++; /* to delete a separator */ - while( ci->nActiveChildren-- ) - DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--); - } + EnterCriticalSection(&ci->lock); + + if( IsZoomed(ci->hwndActiveChild) ) + MDI_RestoreFrameMenu(GetParent(hwnd), ci->hwndActiveChild); + + ci->nActiveChildren = 0; + MDI_RefreshMenu(ci); + + if (ci->child) HeapFree( GetProcessHeap(), 0, ci->child ); if (ci->frameTitle) HeapFree( GetProcessHeap(), 0, ci->frameTitle ); + + LeaveCriticalSection(&ci->lock); + DeleteCriticalSection(&ci->lock); return 0; } case WM_MDIACTIVATE: - if( ci->hwndActiveChild != (HWND)wParam ) + { + HWND hwndActive; + + EnterCriticalSection(&ci->lock); + hwndActive = ci->hwndActiveChild; + LeaveCriticalSection(&ci->lock); + + if( hwndActive != (HWND)wParam ) SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE); return 0; + } case WM_MDICASCADE: return MDICascade(hwnd, ci); case WM_MDICREATE: if (lParam) - return (LRESULT)MDICreateChild( hwnd, ci, (MDICREATESTRUCTA *)lParam, unicode ); + { + if (unicode) + { + MDICREATESTRUCTW *csW = (MDICREATESTRUCTW *)lParam; + return (LRESULT)CreateWindowExW(WS_EX_MDICHILD, csW->szClass, + csW->szTitle, csW->style, + csW->x, csW->y, csW->cx, csW->cy, + hwnd, 0, csW->hOwner, + (LPVOID)csW->lParam); + } + else + { + MDICREATESTRUCTA *csA = (MDICREATESTRUCTA *)lParam; + return (LRESULT)CreateWindowExA(WS_EX_MDICHILD, csA->szClass, + csA->szTitle, csA->style, + csA->x, csA->y, csA->cx, csA->cy, + hwnd, 0, csA->hOwner, + (LPVOID)csA->lParam); + } + } return 0; case WM_MDIDESTROY: return MDIDestroyChild( hwnd, ci, WIN_GetFullHandle( (HWND)wParam ), TRUE ); case WM_MDIGETACTIVE: - if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized != 0); + if (lParam) *(BOOL *)lParam = IsZoomed(ci->hwndActiveChild); return (LRESULT)ci->hwndActiveChild; case WM_MDIICONARRANGE: @@ -1339,7 +1190,7 @@ static LRESULT MDIClientWndProc_common( return MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam ); case WM_MDIREFRESHMENU: - return MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam ); + return MDI_RefreshMenu( ci ); case WM_MDITILE: ci->mdiFlags |= MDIF_NEEDUPDATE; @@ -1366,8 +1217,25 @@ static LRESULT MDIClientWndProc_common( break; case WM_PARENTNOTIFY: - if (LOWORD(wParam) == WM_LBUTTONDOWN) + switch (LOWORD(wParam)) { + case WM_CREATE: + if (GetWindowLongW((HWND)lParam, GWL_EXSTYLE) & WS_EX_MDICHILD) + { + ci->nTotalCreated++; + ci->nActiveChildren++; + + if (!ci->child) + ci->child = HeapAlloc(GetProcessHeap(), 0, sizeof(HWND)); + else + ci->child = HeapReAlloc(GetProcessHeap(), 0, ci->child, sizeof(HWND) * ci->nActiveChildren); + + ci->child[ci->nActiveChildren - 1] = (HWND)lParam; + } + break; + + case WM_LBUTTONDOWN: + { HWND child; POINT pt; pt.x = (short)LOWORD(lParam); @@ -1378,11 +1246,13 @@ static LRESULT MDIClientWndProc_common( if( child && child != hwnd && child != ci->hwndActiveChild ) SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE ); + break; + } } return 0; case WM_SIZE: - if( IsWindow(ci->hwndChildMaximized) ) + if( IsWindow(ci->hwndActiveChild) && IsZoomed(ci->hwndActiveChild) ) { RECT rect; @@ -1391,9 +1261,9 @@ static LRESULT MDIClientWndProc_common( rect.right = LOWORD(lParam); rect.bottom = HIWORD(lParam); - AdjustWindowRectEx(&rect, GetWindowLongA(ci->hwndChildMaximized,GWL_STYLE), - 0, GetWindowLongA(ci->hwndChildMaximized,GWL_EXSTYLE) ); - MoveWindow(ci->hwndChildMaximized, rect.left, rect.top, + AdjustWindowRectEx(&rect, GetWindowLongA(ci->hwndActiveChild, GWL_STYLE), + 0, GetWindowLongA(ci->hwndActiveChild, GWL_EXSTYLE) ); + MoveWindow(ci->hwndActiveChild, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 1); } else @@ -1447,7 +1317,7 @@ LRESULT WINAPI DefFrameProcA( HWND hwnd, DWORD len = MultiByteToWideChar( CP_ACP, 0, (LPSTR)lParam, -1, NULL, 0 ); LPWSTR text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); MultiByteToWideChar( CP_ACP, 0, (LPSTR)lParam, -1, text, len ); - MDI_UpdateFrameText(hwnd, hwndMDIClient, MDI_REPAINTFRAME, text ); + MDI_UpdateFrameText(hwnd, hwndMDIClient, TRUE, text ); HeapFree( GetProcessHeap(), 0, text ); } return 1; /* success. FIXME: check text length */ @@ -1472,6 +1342,8 @@ LRESULT WINAPI DefFrameProcW( HWND hwnd, { MDICLIENTINFO *ci = get_client_info( hwndMDIClient ); + TRACE("%p %p %04x %08x %08lx\n", hwnd, hwndMDIClient, message, wParam, lParam); + if (ci) { switch (message) @@ -1483,7 +1355,7 @@ LRESULT WINAPI DefFrameProcW( HWND hwnd, if (id < ci->idFirstChild || id >= ci->idFirstChild + ci->nActiveChildren) { if( (id - 0xf000) & 0xf00f ) break; - if( !ci->hwndChildMaximized ) break; + if( !IsZoomed(ci->hwndActiveChild) ) break; switch( id ) { case SC_SIZE: @@ -1494,7 +1366,7 @@ LRESULT WINAPI DefFrameProcW( HWND hwnd, case SC_PREVWINDOW: case SC_CLOSE: case SC_RESTORE: - return SendMessageW( ci->hwndChildMaximized, WM_SYSCOMMAND, + return SendMessageW( ci->hwndActiveChild, WM_SYSCOMMAND, wParam, lParam); } } @@ -1506,7 +1378,7 @@ LRESULT WINAPI DefFrameProcW( HWND hwnd, childHwnd = MDI_MoreWindowsDialog(hwndMDIClient); else /* User chose one of the windows listed in the "Windows" menu */ - childHwnd = MDI_GetChildByID(hwndMDIClient,id); + childHwnd = MDI_GetChildByID(hwndMDIClient, id, ci); if( childHwnd ) SendMessageW( hwndMDIClient, WM_MDIACTIVATE, (WPARAM)childHwnd, 0 ); @@ -1519,7 +1391,7 @@ LRESULT WINAPI DefFrameProcW( HWND hwnd, break; case WM_SETTEXT: - MDI_UpdateFrameText(hwnd, hwndMDIClient, MDI_REPAINTFRAME, (LPWSTR)lParam ); + MDI_UpdateFrameText(hwnd, hwndMDIClient, TRUE, (LPWSTR)lParam ); return 1; /* success. FIXME: check text length */ case WM_SETFOCUS: @@ -1534,7 +1406,7 @@ LRESULT WINAPI DefFrameProcW( HWND hwnd, { MDINEXTMENU *next_menu = (MDINEXTMENU *)lParam; - if (!IsIconic(hwnd) && ci->hwndActiveChild && !ci->hwndChildMaximized) + if (!IsIconic(hwnd) && ci->hwndActiveChild && !IsZoomed(ci->hwndActiveChild)) { /* control menu is between the frame system menu and * the first entry of menu bar */ @@ -1567,6 +1439,8 @@ LRESULT WINAPI DefMDIChildProcA( HWND hw HWND client = GetParent(hwnd); MDICLIENTINFO *ci = get_client_info( client ); + TRACE("%p %04x %08x %08lx\n", hwnd, message, wParam, lParam); + hwnd = WIN_GetFullHandle( hwnd ); if (!ci) return DefWindowProcA( hwnd, message, wParam, lParam ); @@ -1574,9 +1448,8 @@ LRESULT WINAPI DefMDIChildProcA( HWND hw { case WM_SETTEXT: DefWindowProcA(hwnd, message, wParam, lParam); - MDI_MenuModifyItem( client, hwnd ); - if( ci->hwndChildMaximized == hwnd ) - MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL ); + if( ci->hwndActiveChild == hwnd && IsZoomed(ci->hwndActiveChild) ) + MDI_UpdateFrameText( GetParent(client), client, TRUE, NULL ); return 1; /* success. FIXME: check text length */ case WM_GETMINMAXINFO: @@ -1604,6 +1477,8 @@ LRESULT WINAPI DefMDIChildProcW( HWND hw HWND client = GetParent(hwnd); MDICLIENTINFO *ci = get_client_info( client ); + TRACE("%p %04x %08x %08lx\n", hwnd, message, wParam, lParam); + hwnd = WIN_GetFullHandle( hwnd ); if (!ci) return DefWindowProcW( hwnd, message, wParam, lParam ); @@ -1611,9 +1486,8 @@ LRESULT WINAPI DefMDIChildProcW( HWND hw { case WM_SETTEXT: DefWindowProcW(hwnd, message, wParam, lParam); - MDI_MenuModifyItem( client, hwnd ); - if( ci->hwndChildMaximized == hwnd ) - MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL ); + if( ci->hwndActiveChild == hwnd && IsZoomed(ci->hwndActiveChild) ) + MDI_UpdateFrameText( GetParent(client), client, TRUE, NULL ); return 1; /* success. FIXME: check text length */ case WM_GETMINMAXINFO: @@ -1639,7 +1513,8 @@ LRESULT WINAPI DefMDIChildProcW( HWND hw switch( wParam ) { case SC_MOVE: - if( ci->hwndChildMaximized == hwnd) return 0; + if( ci->hwndActiveChild == hwnd && IsZoomed(ci->hwndActiveChild)) + return 0; break; case SC_RESTORE: case SC_MINIMIZE: @@ -1647,7 +1522,7 @@ LRESULT WINAPI DefMDIChildProcW( HWND hw GetWindowLongW( hwnd, GWL_STYLE ) | WS_SYSMENU ); break; case SC_MAXIMIZE: - if (ci->hwndChildMaximized == hwnd) + if (ci->hwndActiveChild == hwnd && IsZoomed(ci->hwndActiveChild)) return SendMessageW( GetParent(client), message, wParam, lParam); SetWindowLongW( hwnd, GWL_STYLE, GetWindowLongW( hwnd, GWL_STYLE ) & ~WS_SYSMENU ); @@ -1662,39 +1537,23 @@ LRESULT WINAPI DefMDIChildProcW( HWND hw break; case WM_SETVISIBLE: - if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE; + if (IsZoomed(ci->hwndActiveChild)) ci->mdiFlags &= ~MDIF_NEEDUPDATE; else MDI_PostUpdate(client, ci, SB_BOTH+1); break; case WM_SIZE: - if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED ) + if( wParam != SIZE_MAXIMIZED ) { - ci->hwndChildMaximized = 0; MDI_RestoreFrameMenu( GetParent(client), hwnd ); - MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL ); + MDI_UpdateFrameText( GetParent(client), client, TRUE, NULL ); } if( wParam == SIZE_MAXIMIZED ) { - HWND hMaxChild = ci->hwndChildMaximized; - - if( hMaxChild == hwnd ) break; - if( hMaxChild) - { - SendMessageW( hMaxChild, WM_SETREDRAW, FALSE, 0 ); - MDI_RestoreFrameMenu( GetParent(client), hMaxChild ); - ShowWindow( hMaxChild, SW_SHOWNOACTIVATE ); - SendMessageW( hMaxChild, WM_SETREDRAW, TRUE, 0 ); - } TRACE("maximizing child %p\n", hwnd ); - /* keep track of the maximized window. */ - ci->hwndChildMaximized = hwnd; /* !!! */ - - /* The maximized window should also be the active window */ - MDI_ChildActivate( client, hwnd ); MDI_AugmentFrameMenu( GetParent(client), hwnd ); - MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL ); + MDI_UpdateFrameText( GetParent(client), client, TRUE, NULL ); } if( wParam == SIZE_MINIMIZED ) @@ -1755,29 +1614,13 @@ HWND WINAPI CreateMDIWindowA( HINSTANCE hInstance, /* [in] Handle to application instance */ LPARAM lParam) /* [in] Application-defined value */ { - MDICLIENTINFO *pCi = get_client_info( hWndParent ); - MDICREATESTRUCTA cs; - - TRACE("(%s,%s,%ld,%d,%d,%d,%d,%p,%p,%ld)\n", + TRACE("(%s,%s,%08lx,%d,%d,%d,%d,%p,%p,%08lx)\n", debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y, nWidth,nHeight,hWndParent,hInstance,lParam); - if (!pCi) - { - ERR("bad hwnd for MDI-client: %p\n", hWndParent); - return 0; - } - cs.szClass=lpClassName; - cs.szTitle=lpWindowName; - cs.hOwner=hInstance; - cs.x=X; - cs.y=Y; - cs.cx=nWidth; - cs.cy=nHeight; - cs.style=dwStyle; - cs.lParam=lParam; - - return MDICreateChild(hWndParent, pCi, &cs, FALSE); + return CreateWindowExA(WS_EX_MDICHILD, lpClassName, lpWindowName, + dwStyle, X, Y, nWidth, nHeight, hWndParent, + 0, hInstance, (LPVOID)lParam); } /*********************************************************************** @@ -1799,29 +1642,13 @@ HWND WINAPI CreateMDIWindowW( HINSTANCE hInstance, /* [in] Handle to application instance */ LPARAM lParam) /* [in] Application-defined value */ { - MDICLIENTINFO *pCi = get_client_info( hWndParent ); - MDICREATESTRUCTW cs; - - TRACE("(%s,%s,%ld,%d,%d,%d,%d,%p,%p,%ld)\n", + TRACE("(%s,%s,%08lx,%d,%d,%d,%d,%p,%p,%08lx)\n", debugstr_w(lpClassName), debugstr_w(lpWindowName), dwStyle, X, Y, nWidth, nHeight, hWndParent, hInstance, lParam); - if (!pCi) - { - ERR("bad hwnd for MDI-client: %p\n", hWndParent); - return 0; - } - cs.szClass = lpClassName; - cs.szTitle = lpWindowName; - cs.hOwner = hInstance; - cs.x = X; - cs.y = Y; - cs.cx = nWidth; - cs.cy = nHeight; - cs.style = dwStyle; - cs.lParam = lParam; - - return MDICreateChild(hWndParent, pCi, (MDICREATESTRUCTA *)&cs, TRUE); + return CreateWindowExW(WS_EX_MDICHILD, lpClassName, lpWindowName, + dwStyle, X, Y, nWidth, nHeight, hWndParent, + 0, hInstance, (LPVOID)lParam); } /********************************************************************** @@ -2056,32 +1883,15 @@ static INT_PTR WINAPI MDI_MoreWindowsDlg UINT i; MDICLIENTINFO *ci = get_client_info( (HWND)lParam ); HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX); - HWND *list, *sorted_list; - - if (!(list = WIN_ListChildren( (HWND)lParam ))) return TRUE; - if (!(sorted_list = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(HWND) * ci->nActiveChildren ))) - { - HeapFree( GetProcessHeap(), 0, list ); - return FALSE; - } - - /* Fill the list, sorted by id... */ - for (i = 0; list[i]; i++) - { - UINT id = GetWindowLongW( list[i], GWL_ID ) - ci->idFirstChild; - if (id < ci->nActiveChildren) sorted_list[id] = list[i]; - } - HeapFree( GetProcessHeap(), 0, list ); for (i = 0; i < ci->nActiveChildren; i++) { - WCHAR buffer[128]; + WCHAR buffer[MDI_MAXTITLELENGTH]; - if (!GetWindowTextW( sorted_list[i], buffer, sizeof(buffer)/sizeof(WCHAR) )) + if (!InternalGetWindowText( ci->child[i], buffer, sizeof(buffer)/sizeof(WCHAR) )) continue; SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM)buffer ); - SendMessageW(hListBox, LB_SETITEMDATA, i, (LPARAM)sorted_list[i] ); + SendMessageW(hListBox, LB_SETITEMDATA, i, (LPARAM)ci->child[i] ); length = strlenW(buffer); /* FIXME: should use GetTextExtentPoint */ if (length > widest) widest = length; @@ -2156,28 +1966,3 @@ static HWND MDI_MoreWindowsDialog(HWND h (LPDLGTEMPLATEA) template, hwnd, MDI_MoreWindowsDlgProc, (LPARAM) hwnd); } - -/* - * - * MDI_SwapMenuItems - * - * Will swap the menu IDs for the given 2 positions. - * pos1 and pos2 are menu IDs - * - * - */ - -static void MDI_SwapMenuItems(HWND parent, UINT pos1, UINT pos2) -{ - HWND *list; - int i; - - if (!(list = WIN_ListChildren( parent ))) return; - for (i = 0; list[i]; i++) - { - UINT id = GetWindowLongW( list[i], GWL_ID ); - if (id == pos1) SetWindowLongW( list[i], GWL_ID, pos2 ); - else if (id == pos2) SetWindowLongW( list[i], GWL_ID, pos1 ); - } - HeapFree( GetProcessHeap(), 0, list ); -} diff -u cvs/hq/wine/windows/win.c wine/windows/win.c --- cvs/hq/wine/windows/win.c 2004-01-01 15:33:57.000000000 +0800 +++ wine/windows/win.c 2004-01-16 23:17:36.000000000 +0800 @@ -805,8 +805,29 @@ static void WIN_FixCoordinates( CREATEST { if (cs->style & (WS_CHILD | WS_POPUP)) { - if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0; - if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0; + if (cs->dwExStyle & WS_EX_MDICHILD) + { + POINT pos[2]; + + MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0); + + if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) + { + cs->x = pos[0].x; + cs->y = pos[0].y; + } + if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16 || !cs->cx) + cs->cx = pos[1].x; + if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16 || !cs->cy) + cs->cy = pos[1].y; + } + else + { + if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) + cs->x = cs->y = 0; + if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) + cs->cx = cs->cy = 0; + } } else /* overlapped window */ { @@ -979,7 +1000,7 @@ static HWND WIN_CreateWindowEx( CREATEST { INT sw = SW_SHOW; WND *wndPtr; - HWND hwnd, parent, owner; + HWND hwnd, parent, owner, top_child = 0; BOOL unicode = (type == WIN_PROC_32W); TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n", @@ -993,6 +1014,62 @@ static HWND WIN_CreateWindowEx( CREATEST TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" : ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") ); + /* Fix the styles for MDI children */ + if (cs->dwExStyle & WS_EX_MDICHILD) + { + MDICREATESTRUCTA mdi_cs; + UINT flags = 0; + + wndPtr = WIN_GetPtr(cs->hwndParent); + if (wndPtr && wndPtr != WND_OTHER_PROCESS) + { + flags = wndPtr->flags; + WIN_ReleasePtr(wndPtr); + } + + if (!(flags & WIN_ISMDICLIENT)) + { + WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent); + return 0; + } + + /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children. + * MDICREATESTRUCT members have the originally passed values. + * + * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW + * have the same layout. + */ + mdi_cs.szClass = cs->lpszClass; + mdi_cs.szTitle = cs->lpszName; + mdi_cs.hOwner = cs->hInstance; + mdi_cs.x = cs->x; + mdi_cs.y = cs->y; + mdi_cs.cx = cs->cx; + mdi_cs.cy = cs->cy; + mdi_cs.style = cs->style; + mdi_cs.lParam = (LPARAM)cs->lpCreateParams; + + cs->lpCreateParams = (LPVOID)&mdi_cs; + + if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES) + { + if (cs->style & WS_POPUP) + { + TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n"); + return 0; + } + cs->style |= WS_CHILD | WS_CLIPSIBLINGS; + } + else + { + cs->style &= ~WS_POPUP; + cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION | + WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; + } + + top_child = GetWindow(cs->hwndParent, GW_CHILD); + } + /* Find the parent window */ parent = GetDesktopWindow(); @@ -1136,6 +1213,21 @@ static HWND WIN_CreateWindowEx( CREATEST send_parent_notify( hwnd, WM_CREATE ); if (!IsWindow( hwnd )) return 0; + if (cs->dwExStyle & WS_EX_MDICHILD) + { + if (top_child) + { + /* Restore current maximized child */ + if((cs->style & WS_VISIBLE) && IsZoomed(top_child)) + { + TRACE("Restoring current maximized child %p\n", top_child); + ShowWindow(top_child, SW_SHOWNOACTIVATE); + } + } + + SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0); + } + if (cs->style & WS_VISIBLE) { /* in case WS_VISIBLE got set in the meantime */ @@ -1237,9 +1329,6 @@ HWND WINAPI CreateWindowExA( DWORD exSty CREATESTRUCTA cs; char buffer[256]; - if(exStyle & WS_EX_MDICHILD) - return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data); - /* Find the class atom */ if (HIWORD(className)) @@ -1293,9 +1382,6 @@ HWND WINAPI CreateWindowExW( DWORD exSty CREATESTRUCTW cs; WCHAR buffer[256]; - if(exStyle & WS_EX_MDICHILD) - return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data); - /* Find the class atom */ if (HIWORD(className)) @@ -1398,6 +1484,13 @@ BOOL WINAPI DestroyWindow( HWND hwnd ) TRACE("(%p)\n", hwnd); + /* Hide the window */ + if (!ShowWindow( hwnd, SW_HIDE )) + { + if (hwnd == GetActiveWindow()) WINPOS_ActivateOtherWindow( hwnd ); + } + if (!IsWindow(hwnd)) return TRUE; + /* Look whether the focus is within the tree of windows we will * be destroying. */ @@ -1409,6 +1502,9 @@ BOOL WINAPI DestroyWindow( HWND hwnd ) SetFocus( parent ); } + if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD) + SendMessageW(GetAncestor(hwnd, GA_PARENT), WM_MDIREFRESHMENU, 0, 0); + /* Call hooks */ if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE; @@ -1431,14 +1527,6 @@ BOOL WINAPI DestroyWindow( HWND hwnd ) if (USER_Driver.pResetSelectionOwner) USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */ - /* Hide the window */ - - if (!ShowWindow( hwnd, SW_HIDE )) - { - if (hwnd == GetActiveWindow()) WINPOS_ActivateOtherWindow( hwnd ); - } - if (!IsWindow(hwnd)) return TRUE; - /* Recursively destroy owned windows */ if (!is_child) diff -u cvs/hq/wine/windows/winproc.c wine/windows/winproc.c --- cvs/hq/wine/windows/winproc.c 2003-11-12 14:44:31.000000000 +0800 +++ wine/windows/winproc.c 2004-01-16 17:50:18.000000000 +0800 @@ -671,6 +671,25 @@ INT WINPROC_MapMsg32ATo32W( HWND hwnd, U RtlCreateUnicodeStringFromAsciiz(&usBuffer,(LPCSTR)xs->cs.lpszClass); xs->lpszClass = xs->cs.lpszClass = usBuffer.Buffer; } + + if (GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD) + { + MDICREATESTRUCTW *mdi_cs = (MDICREATESTRUCTW *)HeapAlloc(GetProcessHeap(), 0, + sizeof(*mdi_cs)); + *mdi_cs = *(MDICREATESTRUCTW *)xs->cs.lpCreateParams; + if (HIWORD(mdi_cs->szTitle)) + { + RtlCreateUnicodeStringFromAsciiz(&usBuffer, (LPCSTR)mdi_cs->szTitle); + mdi_cs->szTitle = usBuffer.Buffer; + } + if (HIWORD(mdi_cs->szClass)) + { + RtlCreateUnicodeStringFromAsciiz(&usBuffer, (LPCSTR)mdi_cs->szClass); + mdi_cs->szClass = usBuffer.Buffer; + } + xs->cs.lpCreateParams = mdi_cs; + } + *plparam = (LPARAM)xs; } return 1; @@ -829,6 +848,16 @@ LRESULT WINPROC_UnmapMsg32ATo32W( HWND h struct s *xs = (struct s *)lParam; if (xs->lpszName) HeapFree( GetProcessHeap(), 0, xs->lpszName ); if (xs->lpszClass) HeapFree( GetProcessHeap(), 0, xs->lpszClass ); + + if (GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD) + { + MDICREATESTRUCTW *mdi_cs = (MDICREATESTRUCTW *)xs->cs.lpCreateParams; + if (HIWORD(mdi_cs->szTitle)) + HeapFree(GetProcessHeap(), 0, (LPVOID)mdi_cs->szTitle); + if (HIWORD(mdi_cs->szClass)) + HeapFree(GetProcessHeap(), 0, (LPVOID)mdi_cs->szClass); + HeapFree(GetProcessHeap(), 0, mdi_cs); + } HeapFree( GetProcessHeap(), 0, xs ); } break; @@ -952,6 +981,25 @@ INT WINPROC_MapMsg32WTo32A( HWND hwnd, U if (HIWORD(cs->lpszClass)) cs->lpszClass = HEAP_strdupWtoA( GetProcessHeap(), 0, (LPCWSTR)cs->lpszClass); + + if (GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD) + { + MDICREATESTRUCTA *mdi_cs = (MDICREATESTRUCTA *)HeapAlloc(GetProcessHeap(), 0, + sizeof(*mdi_cs)); + if (!mdi_cs) + { + HeapFree(GetProcessHeap(), 0, cs); + return -1; + } + *mdi_cs = *(MDICREATESTRUCTA *)cs->lpCreateParams; + if (HIWORD(mdi_cs->szTitle)) + mdi_cs->szTitle = HEAP_strdupWtoA(GetProcessHeap(), 0, + (LPCWSTR)mdi_cs->szTitle); + if (HIWORD(mdi_cs->szClass)) + mdi_cs->szClass = HEAP_strdupWtoA(GetProcessHeap(), 0, + (LPCWSTR)mdi_cs->szClass); + cs->lpCreateParams = (LPVOID)mdi_cs; + } *plparam = (LPARAM)cs; } return 1; @@ -1100,6 +1148,15 @@ void WINPROC_UnmapMsg32WTo32A( HWND hwnd HeapFree( GetProcessHeap(), 0, (LPVOID)cs->lpszName ); if (HIWORD(cs->lpszClass)) HeapFree( GetProcessHeap(), 0, (LPVOID)cs->lpszClass ); + if (GetWindowLongA(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD) + { + MDICREATESTRUCTA *mdi_cs = (MDICREATESTRUCTA *)cs->lpCreateParams; + if (HIWORD(mdi_cs->szTitle)) + HeapFree(GetProcessHeap(), 0, (LPVOID)mdi_cs->szTitle); + if (HIWORD(mdi_cs->szClass)) + HeapFree(GetProcessHeap(), 0, (LPVOID)mdi_cs->szClass); + HeapFree(GetProcessHeap(), 0, mdi_cs); + } HeapFree( GetProcessHeap(), 0, cs ); } break;