Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmdi.c
Go to the documentation of this file.
00001 /* MDI.C 00002 * 00003 * Copyright 1994, Bob Amstadt 00004 * 1995,1996 Alex Korobka 00005 * 00006 * This file contains routines to support MDI (Multiple Document 00007 * Interface) features . 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 * This library is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00022 * 00023 * Notes: Fairly complete implementation. 00024 * Also, Excel and WinWord do _not_ use MDI so if you're trying 00025 * to fix them look elsewhere. 00026 * 00027 * Notes on how the "More Windows..." is implemented: 00028 * 00029 * When we have more than 9 opened windows, a "More Windows..." 00030 * option appears in the "Windows" menu. Each child window has 00031 * a WND* associated with it, accesible via the children list of 00032 * the parent window. This WND* has a wIDmenu member, which reflects 00033 * the position of the child in the window list. For example, with 00034 * 9 child windows, we could have the following pattern: 00035 * 00036 * 00037 * 00038 * Name of the child window pWndChild->wIDmenu 00039 * Doc1 5000 00040 * Doc2 5001 00041 * Doc3 5002 00042 * Doc4 5003 00043 * Doc5 5004 00044 * Doc6 5005 00045 * Doc7 5006 00046 * Doc8 5007 00047 * Doc9 5008 00048 * 00049 * 00050 * The "Windows" menu, as the "More windows..." dialog, are constructed 00051 * in this order. If we add a child, we would have the following list: 00052 * 00053 * 00054 * Name of the child window pWndChild->wIDmenu 00055 * Doc1 5000 00056 * Doc2 5001 00057 * Doc3 5002 00058 * Doc4 5003 00059 * Doc5 5004 00060 * Doc6 5005 00061 * Doc7 5006 00062 * Doc8 5007 00063 * Doc9 5008 00064 * Doc10 5009 00065 * 00066 * But only 5000 to 5008 would be displayed in the "Windows" menu. We want 00067 * the last created child to be in the menu, so we swap the last child with 00068 * the 9th... Doc9 will be accessible via the "More Windows..." option. 00069 * 00070 * Doc1 5000 00071 * Doc2 5001 00072 * Doc3 5002 00073 * Doc4 5003 00074 * Doc5 5004 00075 * Doc6 5005 00076 * Doc7 5006 00077 * Doc8 5007 00078 * Doc9 5009 00079 * Doc10 5008 00080 * 00081 */ 00082 00083 #include <user32.h> 00084 00085 #include <wine/debug.h> 00086 00087 WINE_DEFAULT_DEBUG_CHANNEL(mdi); 00088 00089 #define MDI_MAXTITLELENGTH 0xa1 00090 00091 #define WM_MDICALCCHILDSCROLL 0x10ac /* this is exactly what Windows uses */ 00092 00093 /* "More Windows..." definitions */ 00094 #define MDI_MOREWINDOWSLIMIT 9 /* after this number of windows, a "More Windows..." 00095 option will appear under the Windows menu */ 00096 #define MDI_IDC_LISTBOX 100 00097 #define IDS_MDI_MOREWINDOWS 13 00098 00099 #define MDIF_NEEDUPDATE 0x0001 00100 00101 typedef struct 00102 { 00103 /* At some points, particularly when switching MDI children, active and 00104 * maximized MDI children may be not the same window, so we need to track 00105 * them separately. 00106 * The only place where we switch to/from maximized state is DefMDIChildProc 00107 * WM_SIZE/SIZE_MAXIMIZED handler. We get that notification only after the 00108 * ShowWindow(SW_SHOWMAXIMIZED) request, therefore window is guaranteed to 00109 * be visible at the time we get the notification, and it's safe to assume 00110 * that hwndChildMaximized is always visible. 00111 * If the app plays games with WS_VISIBLE, WS_MAXIMIZE or any other window 00112 * states it must keep coherency with USER32 on its own. This is true for 00113 * Windows as well. 00114 */ 00115 UINT nActiveChildren; 00116 HWND hwndChildMaximized; 00117 HWND hwndActiveChild; 00118 HWND *child; /* array of tracked children */ 00119 HMENU hFrameMenu; 00120 HMENU hWindowMenu; 00121 UINT idFirstChild; 00122 LPWSTR frameTitle; 00123 UINT nTotalCreated; 00124 UINT mdiFlags; 00125 UINT sbRecalc; /* SB_xxx flags for scrollbar fixup */ 00126 HBITMAP hBmpClose; /* ReactOS modification */ 00127 } MDICLIENTINFO; 00128 00129 //static HBITMAP hBmpClose = 0; 00130 00131 /* ----------------- declarations ----------------- */ 00132 static void MDI_UpdateFrameText( HWND, HWND, BOOL, LPCWSTR); 00133 static BOOL MDI_AugmentFrameMenu( HWND, HWND ); 00134 static BOOL MDI_RestoreFrameMenu( HWND, HWND, HBITMAP ); 00135 static LONG MDI_ChildActivate( HWND, HWND ); 00136 static LRESULT MDI_RefreshMenu(MDICLIENTINFO *); 00137 00138 static HWND MDI_MoreWindowsDialog(HWND); 00139 00140 HWND* WIN_ListChildren (HWND hWndparent) 00141 { 00142 00143 DWORD dwCount = 0; 00144 HWND* pHwnd = NULL; 00145 HANDLE hHeap; 00146 NTSTATUS Status; 00147 00148 Status = NtUserBuildHwndList ( NULL, hWndparent, FALSE, 0, 0, NULL, &dwCount ); 00149 00150 if ( !NT_SUCCESS( Status ) ) 00151 return 0; 00152 00153 /* allocate buffer to receive HWND handles */ 00154 hHeap = GetProcessHeap(); 00155 00156 pHwnd = HeapAlloc ( hHeap, 0, sizeof(HWND)*(dwCount+1) ); 00157 if ( !pHwnd ) 00158 { 00159 SetLastError ( ERROR_NOT_ENOUGH_MEMORY ); 00160 return 0; 00161 } 00162 00163 /* now call kernel again to fill the buffer this time */ 00164 Status = NtUserBuildHwndList (NULL, hWndparent, FALSE, 0, 0, pHwnd, &dwCount ); 00165 00166 if ( !NT_SUCCESS( Status ) ) 00167 { 00168 if ( pHwnd ) 00169 HeapFree ( hHeap, 0, pHwnd ); 00170 return 0; 00171 } 00172 00173 pHwnd[dwCount] = (HWND) 0; 00174 00175 return pHwnd; 00176 } 00177 00178 #ifdef __REACTOS__ 00179 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 00180 void WINAPI CalcChildScroll(HWND hwnd, INT scroll); 00181 #endif 00182 00183 /* -------- Miscellaneous service functions ---------- 00184 * 00185 * MDI_GetChildByID 00186 */ 00187 static HWND MDI_GetChildByID(HWND hwnd, UINT id, MDICLIENTINFO *ci) 00188 { 00189 int i; 00190 00191 for (i = 0; ci->nActiveChildren; i++) 00192 { 00193 if (GetWindowLongPtrW( ci->child[i], GWLP_ID ) == id) 00194 return ci->child[i]; 00195 } 00196 return 0; 00197 } 00198 00199 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc) 00200 { 00201 if( !(ci->mdiFlags & MDIF_NEEDUPDATE) ) 00202 { 00203 ci->mdiFlags |= MDIF_NEEDUPDATE; 00204 PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0); 00205 } 00206 ci->sbRecalc = recalc; 00207 } 00208 00209 00210 /********************************************************************* 00211 * MDIClient class descriptor 00212 */ 00213 const struct builtin_class_descr MDICLIENT_builtin_class = 00214 { 00215 L"MDIClient", /* name */ 00216 0, /* style */ 00217 MDIClientWndProcA, /* procA */ 00218 MDIClientWndProcW, /* procW */ 00219 sizeof(MDICLIENTINFO), /* extra */ 00220 IDC_ARROW, /* cursor */ 00221 (HBRUSH)(COLOR_APPWORKSPACE+1) /* brush */ 00222 }; 00223 00224 00225 static MDICLIENTINFO *get_client_info( HWND client ) 00226 { 00227 #ifdef __REACTOS__ 00228 return (MDICLIENTINFO *)GetWindowLongPtr(client, 0); 00229 #else 00230 MDICLIENTINFO *ret = NULL; 00231 WND *win = WIN_GetPtr( client ); 00232 if (win) 00233 { 00234 if (win == WND_OTHER_PROCESS || win == WND_DESKTOP) 00235 { 00236 if (IsWindow(client)) WARN( "client %p belongs to other process\n", client ); 00237 return NULL; 00238 } 00239 if (win->flags & WIN_ISMDICLIENT) 00240 ret = (MDICLIENTINFO *)win->wExtra; 00241 else 00242 WARN( "%p is not an MDI client\n", client ); 00243 WIN_ReleasePtr( win ); 00244 } 00245 return ret; 00246 #endif 00247 } 00248 00249 static BOOL is_close_enabled(HWND hwnd, HMENU hSysMenu) 00250 { 00251 if (GetClassLongPtrW(hwnd, GCL_STYLE) & CS_NOCLOSE) return FALSE; 00252 00253 if (!hSysMenu) hSysMenu = GetSystemMenu(hwnd, FALSE); 00254 if (hSysMenu) 00255 { 00256 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND); 00257 if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED))) 00258 return FALSE; 00259 } 00260 return TRUE; 00261 } 00262 00263 /********************************************************************** 00264 * MDI_GetWindow 00265 * 00266 * returns "activateable" child different from the current or zero 00267 */ 00268 static HWND MDI_GetWindow(MDICLIENTINFO *clientInfo, HWND hWnd, BOOL bNext, 00269 DWORD dwStyleMask ) 00270 { 00271 int i; 00272 HWND *list; 00273 HWND last = 0; 00274 00275 dwStyleMask |= WS_DISABLED | WS_VISIBLE; 00276 if( !hWnd ) hWnd = clientInfo->hwndActiveChild; 00277 00278 if (!(list = WIN_ListChildren( GetParent(hWnd) ))) return 0; 00279 i = 0; 00280 /* start from next after hWnd */ 00281 while (list[i] && list[i] != hWnd) i++; 00282 if (list[i]) i++; 00283 00284 for ( ; list[i]; i++) 00285 { 00286 if (GetWindow( list[i], GW_OWNER )) continue; 00287 if ((GetWindowLongPtrW( list[i], GWL_STYLE ) & dwStyleMask) != WS_VISIBLE) continue; 00288 last = list[i]; 00289 if (bNext) goto found; 00290 } 00291 /* now restart from the beginning */ 00292 for (i = 0; list[i] && list[i] != hWnd; i++) 00293 { 00294 if (GetWindow( list[i], GW_OWNER )) continue; 00295 if ((GetWindowLongPtrW( list[i], GWL_STYLE ) & dwStyleMask) != WS_VISIBLE) continue; 00296 last = list[i]; 00297 if (bNext) goto found; 00298 } 00299 found: 00300 HeapFree( GetProcessHeap(), 0, list ); 00301 return last; 00302 } 00303 00304 /********************************************************************** 00305 * MDI_CalcDefaultChildPos 00306 * 00307 * It seems that the default height is about 2/3 of the client rect 00308 */ 00309 void MDI_CalcDefaultChildPos( HWND hwndClient, INT total, LPPOINT lpPos, INT delta, UINT *id ) 00310 { 00311 INT nstagger; 00312 RECT rect; 00313 INT spacing = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME) - 1; 00314 00315 if (total < 0) /* we are called from CreateWindow */ 00316 { 00317 MDICLIENTINFO *ci = get_client_info(hwndClient); 00318 total = ci ? ci->nTotalCreated : 0; // Do not portsync wine 00319 *id = ci ? ci->idFirstChild + ci->nActiveChildren : 0; // Do not portsync wine 00320 TRACE("MDI child id %04x\n", *id); 00321 } 00322 00323 GetClientRect( hwndClient, &rect ); 00324 if( rect.bottom - rect.top - delta >= spacing ) 00325 rect.bottom -= delta; 00326 00327 nstagger = (rect.bottom - rect.top)/(3 * spacing); 00328 lpPos[1].x = (rect.right - rect.left - nstagger * spacing); 00329 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing); 00330 lpPos[0].x = lpPos[0].y = spacing * (total%(nstagger+1)); 00331 } 00332 00333 /********************************************************************** 00334 * MDISetMenu 00335 */ 00336 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame, 00337 HMENU hmenuWindow) 00338 { 00339 MDICLIENTINFO *ci; 00340 HWND hwndFrame = GetParent(hwnd); 00341 00342 TRACE("%p %p %p\n", hwnd, hmenuFrame, hmenuWindow); 00343 00344 if (hmenuFrame && !IsMenu(hmenuFrame)) 00345 { 00346 WARN("hmenuFrame is not a menu handle\n"); 00347 return 0L; 00348 } 00349 00350 if (hmenuWindow && !IsMenu(hmenuWindow)) 00351 { 00352 WARN("hmenuWindow is not a menu handle\n"); 00353 return 0L; 00354 } 00355 00356 if (!(ci = get_client_info( hwnd ))) return 0; 00357 00358 TRACE("old frame menu %p, old window menu %p\n", ci->hFrameMenu, ci->hWindowMenu); 00359 00360 if (hmenuFrame) 00361 { 00362 if (hmenuFrame == ci->hFrameMenu) return (LRESULT)hmenuFrame; 00363 00364 if (ci->hwndChildMaximized) 00365 MDI_RestoreFrameMenu( hwndFrame, ci->hwndChildMaximized, ci->hBmpClose ); 00366 } 00367 00368 if( hmenuWindow && hmenuWindow != ci->hWindowMenu ) 00369 { 00370 /* delete menu items from ci->hWindowMenu 00371 * and add them to hmenuWindow */ 00372 /* Agent newsreader calls this function with ci->hWindowMenu == NULL */ 00373 if( ci->hWindowMenu && ci->nActiveChildren ) 00374 { 00375 UINT nActiveChildren_old = ci->nActiveChildren; 00376 00377 /* Remove all items from old Window menu */ 00378 ci->nActiveChildren = 0; 00379 MDI_RefreshMenu(ci); 00380 00381 ci->hWindowMenu = hmenuWindow; 00382 00383 /* Add items to the new Window menu */ 00384 ci->nActiveChildren = nActiveChildren_old; 00385 MDI_RefreshMenu(ci); 00386 } 00387 else 00388 ci->hWindowMenu = hmenuWindow; 00389 } 00390 00391 if (hmenuFrame) 00392 { 00393 SetMenu(hwndFrame, hmenuFrame); 00394 if( hmenuFrame != ci->hFrameMenu ) 00395 { 00396 HMENU oldFrameMenu = ci->hFrameMenu; 00397 00398 ci->hFrameMenu = hmenuFrame; 00399 if (ci->hwndChildMaximized) 00400 MDI_AugmentFrameMenu( hwndFrame, ci->hwndChildMaximized ); 00401 00402 return (LRESULT)oldFrameMenu; 00403 } 00404 } 00405 else 00406 { 00407 /* SetMenu() may already have been called, meaning that this window 00408 * already has its menu. But they may have done a SetMenu() on 00409 * an MDI window, and called MDISetMenu() after the fact, meaning 00410 * that the "if" to this "else" wouldn't catch the need to 00411 * augment the frame menu. 00412 */ 00413 if( ci->hwndChildMaximized ) 00414 MDI_AugmentFrameMenu( hwndFrame, ci->hwndChildMaximized ); 00415 } 00416 00417 return 0; 00418 } 00419 00420 /********************************************************************** 00421 * MDIRefreshMenu 00422 */ 00423 static LRESULT MDI_RefreshMenu(MDICLIENTINFO *ci) 00424 { 00425 UINT i, count, visible, id; 00426 WCHAR buf[MDI_MAXTITLELENGTH]; 00427 00428 TRACE("children %u, window menu %p\n", ci->nActiveChildren, ci->hWindowMenu); 00429 00430 if (!ci->hWindowMenu) 00431 return 0; 00432 00433 if (!IsMenu(ci->hWindowMenu)) 00434 { 00435 WARN("Window menu handle %p is no more valid\n", ci->hWindowMenu); 00436 return 0; 00437 } 00438 00439 /* Windows finds the last separator in the menu, and if after it 00440 * there is a menu item with MDI magic ID removes all existing 00441 * menu items after it, and then adds visible MDI children. 00442 */ 00443 count = GetMenuItemCount(ci->hWindowMenu); 00444 for (i = 0; i < count; i++) 00445 { 00446 MENUITEMINFOW mii; 00447 00448 memset(&mii, 0, sizeof(mii)); 00449 mii.cbSize = sizeof(mii); 00450 mii.fMask = MIIM_TYPE; 00451 if (GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii)) 00452 { 00453 if (mii.fType & MF_SEPARATOR) 00454 { 00455 /* Windows checks only ID of the menu item */ 00456 memset(&mii, 0, sizeof(mii)); 00457 mii.cbSize = sizeof(mii); 00458 mii.fMask = MIIM_ID; 00459 if (GetMenuItemInfoW(ci->hWindowMenu, i + 1, TRUE, &mii)) 00460 { 00461 if (mii.wID == ci->idFirstChild) 00462 { 00463 TRACE("removing %u items including separator\n", count - i); 00464 while (RemoveMenu(ci->hWindowMenu, i, MF_BYPOSITION)) 00465 /* nothing */; 00466 00467 break; 00468 } 00469 } 00470 } 00471 } 00472 } 00473 00474 visible = 0; 00475 for (i = 0; i < ci->nActiveChildren; i++) 00476 { 00477 if (GetWindowLongPtrW(ci->child[i], GWL_STYLE) & WS_VISIBLE) 00478 { 00479 id = ci->idFirstChild + visible; 00480 00481 if (visible == MDI_MOREWINDOWSLIMIT) 00482 { 00483 LoadStringW(User32Instance, IDS_MDI_MOREWINDOWS, buf, sizeof(buf)/sizeof(WCHAR)); 00484 AppendMenuW(ci->hWindowMenu, MF_STRING, id, buf); 00485 break; 00486 } 00487 00488 if (!visible) 00489 /* Visio expects that separator has id 0 */ 00490 AppendMenuW(ci->hWindowMenu, MF_SEPARATOR, 0, NULL); 00491 00492 visible++; 00493 00494 SetWindowLongPtrW(ci->child[i], GWLP_ID, id); 00495 00496 buf[0] = '&'; 00497 buf[1] = '0' + visible; 00498 buf[2] = ' '; 00499 InternalGetWindowText(ci->child[i], buf + 3, sizeof(buf)/sizeof(WCHAR) - 3); 00500 TRACE("Adding %p, id %u %s\n", ci->child[i], id, debugstr_w(buf)); 00501 AppendMenuW(ci->hWindowMenu, MF_STRING, id, buf); 00502 00503 if (ci->child[i] == ci->hwndActiveChild) 00504 CheckMenuItem(ci->hWindowMenu, id, MF_CHECKED); 00505 } 00506 else 00507 TRACE("MDI child %p is not visible, skipping\n", ci->child[i]); 00508 } 00509 00510 return (LRESULT)ci->hFrameMenu; 00511 } 00512 00513 00514 /* ------------------ MDI child window functions ---------------------- */ 00515 00516 /********************************************************************** 00517 * MDI_ChildGetMinMaxInfo 00518 * 00519 * Note: The rule here is that client rect of the maximized MDI child 00520 * is equal to the client rect of the MDI client window. 00521 */ 00522 static void MDI_ChildGetMinMaxInfo( HWND client, HWND hwnd, MINMAXINFO* lpMinMax ) 00523 { 00524 RECT rect; 00525 00526 GetClientRect( client, &rect ); 00527 AdjustWindowRectEx( &rect, GetWindowLongPtrW( hwnd, GWL_STYLE ), 00528 0, GetWindowLongPtrW( hwnd, GWL_EXSTYLE )); 00529 00530 lpMinMax->ptMaxSize.x = rect.right -= rect.left; 00531 lpMinMax->ptMaxSize.y = rect.bottom -= rect.top; 00532 00533 lpMinMax->ptMaxPosition.x = rect.left; 00534 lpMinMax->ptMaxPosition.y = rect.top; 00535 00536 TRACE("max rect (%ld,%ld - %ld, %ld)\n", 00537 rect.left,rect.top,rect.right,rect.bottom); 00538 } 00539 00540 /********************************************************************** 00541 * MDI_SwitchActiveChild 00542 * 00543 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is 00544 * being activated 00545 */ 00546 static void MDI_SwitchActiveChild( MDICLIENTINFO *ci, HWND hwndTo, BOOL activate ) 00547 { 00548 HWND hwndPrev; 00549 00550 hwndPrev = ci->hwndActiveChild; 00551 00552 TRACE("from %p, to %p\n", hwndPrev, hwndTo); 00553 00554 if ( hwndTo != hwndPrev ) 00555 { 00556 BOOL was_zoomed = IsZoomed(hwndPrev); 00557 00558 if (was_zoomed) 00559 { 00560 /* restore old MDI child */ 00561 SendMessageW( hwndPrev, WM_SETREDRAW, FALSE, 0 ); 00562 ShowWindow( hwndPrev, SW_RESTORE ); 00563 SendMessageW( hwndPrev, WM_SETREDRAW, TRUE, 0 ); 00564 00565 /* activate new MDI child */ 00566 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE ); 00567 /* maximize new MDI child */ 00568 ShowWindow( hwndTo, SW_MAXIMIZE ); 00569 } 00570 /* activate new MDI child */ 00571 SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | (activate ? 0 : SWP_NOACTIVATE) ); 00572 } 00573 } 00574 00575 00576 /********************************************************************** 00577 * MDIDestroyChild 00578 */ 00579 static LRESULT MDIDestroyChild( HWND client, MDICLIENTINFO *ci, 00580 HWND child, BOOL flagDestroy ) 00581 { 00582 UINT i; 00583 00584 TRACE("# of managed children %u\n", ci->nActiveChildren); 00585 00586 if( child == ci->hwndActiveChild ) 00587 { 00588 HWND next = MDI_GetWindow(ci, child, TRUE, 0); 00589 if (next) 00590 MDI_SwitchActiveChild(ci, next, TRUE); 00591 else 00592 { 00593 ShowWindow(child, SW_HIDE); 00594 if (child == ci->hwndChildMaximized) 00595 { 00596 HWND frame = GetParent(client); 00597 MDI_RestoreFrameMenu(frame, child, ci->hBmpClose); 00598 ci->hwndChildMaximized = 0; 00599 MDI_UpdateFrameText(frame, client, TRUE, NULL); 00600 } 00601 if (flagDestroy) 00602 MDI_ChildActivate(client, 0); 00603 } 00604 } 00605 00606 for (i = 0; i < ci->nActiveChildren; i++) 00607 { 00608 if (ci->child[i] == child) 00609 { 00610 HWND *new_child = HeapAlloc(GetProcessHeap(), 0, (ci->nActiveChildren - 1) * sizeof(HWND)); 00611 if (new_child != NULL) 00612 { 00613 memcpy(new_child, ci->child, i * sizeof(HWND)); 00614 if (i + 1 < ci->nActiveChildren) 00615 memcpy(new_child + i, ci->child + i + 1, (ci->nActiveChildren - i - 1) * sizeof(HWND)); 00616 HeapFree(GetProcessHeap(), 0, ci->child); 00617 ci->child = new_child; 00618 } 00619 else 00620 { 00621 UINT c; 00622 for (c = i; c < ci->nActiveChildren - 1; c++) 00623 { 00624 ci->child[c] = ci->child[c+1]; 00625 } 00626 } 00627 00628 ci->nActiveChildren--; 00629 break; 00630 } 00631 } 00632 00633 if (flagDestroy) 00634 { 00635 SendMessageW(client, WM_MDIREFRESHMENU, 0, 0); 00636 MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1); 00637 DestroyWindow(child); 00638 } 00639 00640 TRACE("child destroyed - %p\n", child); 00641 return 0; 00642 } 00643 00644 00645 /********************************************************************** 00646 * MDI_ChildActivate 00647 * 00648 * Called in response to WM_CHILDACTIVATE, or when last MDI child 00649 * is being deactivated. 00650 */ 00651 static LONG MDI_ChildActivate( HWND client, HWND child ) 00652 { 00653 MDICLIENTINFO *clientInfo; 00654 HWND prevActiveWnd, frame; 00655 BOOL isActiveFrameWnd; 00656 00657 clientInfo = get_client_info( client ); 00658 00659 if (clientInfo->hwndActiveChild == child) return 0; 00660 00661 TRACE("%p\n", child); 00662 00663 frame = GetParent(client); 00664 isActiveFrameWnd = (GetActiveWindow() == frame); 00665 prevActiveWnd = clientInfo->hwndActiveChild; 00666 00667 /* deactivate prev. active child */ 00668 if(prevActiveWnd) 00669 { 00670 SendMessageW( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L ); 00671 SendMessageW( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd, (LPARAM)child); 00672 } 00673 00674 MDI_SwitchActiveChild( clientInfo, child, FALSE ); 00675 clientInfo->hwndActiveChild = child; 00676 00677 MDI_RefreshMenu(clientInfo); 00678 00679 if( isActiveFrameWnd ) 00680 { 00681 SendMessageW( child, WM_NCACTIVATE, TRUE, 0L); 00682 /* Let the client window manage focus for children, but if the focus 00683 * is already on the client (for instance this is the 1st child) then 00684 * SetFocus won't work. It appears that Windows sends WM_SETFOCUS 00685 * manually in this case. 00686 */ 00687 if (SetFocus( client ) == client) 00688 SendMessageW( client, WM_SETFOCUS, (WPARAM)client, 0 ); 00689 } 00690 00691 SendMessageW( child, WM_MDIACTIVATE, (WPARAM)prevActiveWnd, (LPARAM)child ); 00692 return TRUE; 00693 } 00694 00695 /* -------------------- MDI client window functions ------------------- */ 00696 00697 /********************************************************************** 00698 * CreateMDIMenuBitmap 00699 */ 00700 static HBITMAP CreateMDIMenuBitmap(void) 00701 { 00702 HDC hDCSrc = CreateCompatibleDC(0); 00703 HDC hDCDest = CreateCompatibleDC(hDCSrc); 00704 HBITMAP hbClose = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_OLD_CLOSE) ); 00705 HBITMAP hbCopy; 00706 HBITMAP hobjSrc, hobjDest; 00707 00708 hobjSrc = SelectObject(hDCSrc, hbClose); 00709 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE)); 00710 hobjDest = SelectObject(hDCDest, hbCopy); 00711 00712 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE), 00713 hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY); 00714 00715 SelectObject(hDCSrc, hobjSrc); 00716 DeleteObject(hbClose); 00717 DeleteDC(hDCSrc); 00718 00719 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) ); 00720 00721 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL ); 00722 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1); 00723 00724 SelectObject(hDCDest, hobjSrc ); 00725 SelectObject(hDCDest, hobjDest); 00726 DeleteDC(hDCDest); 00727 00728 return hbCopy; 00729 } 00730 00731 /********************************************************************** 00732 * MDICascade 00733 */ 00734 static LONG MDICascade( HWND client, MDICLIENTINFO *ci ) 00735 { 00736 HWND *win_array; 00737 BOOL has_icons = FALSE; 00738 int i, total; 00739 00740 if (ci->hwndChildMaximized) 00741 SendMessageW(client, WM_MDIRESTORE, (WPARAM)ci->hwndChildMaximized, 0); 00742 00743 if (ci->nActiveChildren == 0) return 0; 00744 00745 if (!(win_array = WIN_ListChildren( client ))) return 0; 00746 00747 /* remove all the windows we don't want */ 00748 for (i = total = 0; win_array[i]; i++) 00749 { 00750 if (!IsWindowVisible( win_array[i] )) continue; 00751 if (GetWindow( win_array[i], GW_OWNER )) continue; /* skip owned windows */ 00752 if (IsIconic( win_array[i] )) 00753 { 00754 has_icons = TRUE; 00755 continue; 00756 } 00757 win_array[total++] = win_array[i]; 00758 } 00759 win_array[total] = 0; 00760 00761 if (total) 00762 { 00763 INT delta = 0, n = 0, i; 00764 POINT pos[2]; 00765 if (has_icons) delta = GetSystemMetrics(SM_CYICONSPACING) + GetSystemMetrics(SM_CYICON); 00766 00767 /* walk the list (backwards) and move windows */ 00768 for (i = total - 1; i >= 0; i--) 00769 { 00770 LONG style; 00771 LONG posOptions = SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER; 00772 00773 MDI_CalcDefaultChildPos(client, n++, pos, delta, NULL); 00774 TRACE("move %p to (%ld,%ld) size [%ld,%ld]\n", 00775 win_array[i], pos[0].x, pos[0].y, pos[1].x, pos[1].y); 00776 style = GetWindowLongW(win_array[i], GWL_STYLE); 00777 00778 if (!(style & WS_SIZEBOX)) posOptions |= SWP_NOSIZE; 00779 SetWindowPos( win_array[i], 0, pos[0].x, pos[0].y, pos[1].x, pos[1].y, 00780 posOptions); 00781 } 00782 } 00783 HeapFree( GetProcessHeap(), 0, win_array ); 00784 00785 if (has_icons) ArrangeIconicWindows( client ); 00786 return 0; 00787 } 00788 00789 /********************************************************************** 00790 * MDITile 00791 */ 00792 static void MDITile( HWND client, MDICLIENTINFO *ci, WPARAM wParam ) 00793 { 00794 HWND *win_array; 00795 int i, total; 00796 BOOL has_icons = FALSE; 00797 00798 if (ci->hwndChildMaximized) 00799 SendMessageW(client, WM_MDIRESTORE, (WPARAM)ci->hwndChildMaximized, 0); 00800 00801 if (ci->nActiveChildren == 0) return; 00802 00803 if (!(win_array = WIN_ListChildren( client ))) return; 00804 00805 /* remove all the windows we don't want */ 00806 for (i = total = 0; win_array[i]; i++) 00807 { 00808 if (!IsWindowVisible( win_array[i] )) continue; 00809 if (GetWindow( win_array[i], GW_OWNER )) continue; /* skip owned windows (icon titles) */ 00810 if (IsIconic( win_array[i] )) 00811 { 00812 has_icons = TRUE; 00813 continue; 00814 } 00815 if ((wParam & MDITILE_SKIPDISABLED) && !IsWindowEnabled( win_array[i] )) continue; 00816 win_array[total++] = win_array[i]; 00817 } 00818 win_array[total] = 0; 00819 00820 TRACE("%u windows to tile\n", total); 00821 00822 if (total) 00823 { 00824 HWND *pWnd = win_array; 00825 RECT rect; 00826 int x, y, xsize, ysize; 00827 int rows, columns, r, c, i; 00828 00829 GetClientRect(client,&rect); 00830 rows = (int) sqrt((double)total); 00831 columns = total / rows; 00832 00833 if( wParam & MDITILE_HORIZONTAL ) /* version >= 3.1 */ 00834 { 00835 i = rows; 00836 rows = columns; /* exchange r and c */ 00837 columns = i; 00838 } 00839 00840 if (has_icons) 00841 { 00842 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON); 00843 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y; 00844 } 00845 00846 ysize = rect.bottom / rows; 00847 xsize = rect.right / columns; 00848 00849 for (x = i = 0, c = 1; c <= columns && *pWnd; c++) 00850 { 00851 if (c == columns) 00852 { 00853 rows = total - i; 00854 ysize = rect.bottom / rows; 00855 } 00856 00857 y = 0; 00858 for (r = 1; r <= rows && *pWnd; r++, i++) 00859 { 00860 LONG posOptions = SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER; 00861 LONG style = GetWindowLongW(win_array[i], GWL_STYLE); 00862 if (!(style & WS_SIZEBOX)) posOptions |= SWP_NOSIZE; 00863 00864 SetWindowPos(*pWnd, 0, x, y, xsize, ysize, posOptions); 00865 y += ysize; 00866 pWnd++; 00867 } 00868 x += xsize; 00869 } 00870 } 00871 HeapFree( GetProcessHeap(), 0, win_array ); 00872 if (has_icons) ArrangeIconicWindows( client ); 00873 } 00874 00875 /* ----------------------- Frame window ---------------------------- */ 00876 00877 00878 /********************************************************************** 00879 * MDI_AugmentFrameMenu 00880 */ 00881 static BOOL MDI_AugmentFrameMenu( HWND frame, HWND hChild ) 00882 { 00883 HMENU menu = GetMenu( frame ); 00884 HMENU hSysPopup = 0; 00885 HBITMAP hSysMenuBitmap = 0; 00886 HICON hIcon; 00887 INT nItems; 00888 UINT iId; 00889 00890 TRACE("frame %p,child %p\n",frame,hChild); 00891 00892 if( !menu ) return 0; 00894 /* if the system buttons already exist do not add them again */ 00895 nItems = GetMenuItemCount(menu) - 1; 00896 iId = GetMenuItemID(menu,nItems) ; 00897 if (iId == SC_RESTORE || iId == SC_CLOSE) 00898 return 0; 00899 00900 /* create a copy of sysmenu popup and insert it into frame menu bar */ 00901 if (!(hSysPopup = GetSystemMenu(hChild, FALSE))) 00902 { 00903 TRACE("child %p doesn't have a system menu\n", hChild); 00904 return 0; 00905 } 00906 00907 AppendMenuW(menu, MF_HELP | MF_BITMAP, 00908 SC_MINIMIZE, (LPCWSTR)HBMMENU_MBAR_MINIMIZE ) ; 00909 AppendMenuW(menu, MF_HELP | MF_BITMAP, 00910 SC_RESTORE, (LPCWSTR)HBMMENU_MBAR_RESTORE ); 00911 AppendMenuW(menu, MF_HELP | MF_BITMAP, 00912 SC_CLOSE, is_close_enabled(hChild, hSysPopup) ? 00913 (LPCWSTR)HBMMENU_MBAR_CLOSE : (LPCWSTR)HBMMENU_MBAR_CLOSE_D ); 00914 00915 /* The system menu is replaced by the child icon */ 00916 hIcon = (HICON)GetClassLongPtrW(hChild, GCLP_HICONSM); 00917 if (!hIcon) 00918 hIcon = (HICON)GetClassLongPtrW(hChild, GCLP_HICON); 00919 if (!hIcon) 00920 hIcon = LoadIconW(NULL, IDI_APPLICATION); 00922 if (hIcon) 00923 { 00924 HDC hMemDC; 00925 HBITMAP hBitmap, hOldBitmap; 00926 HBRUSH hBrush; 00927 HDC hdc = GetDC(hChild); 00928 00929 if (hdc) 00930 { 00931 int cx, cy; 00932 cx = GetSystemMetrics(SM_CXSMICON); 00933 cy = GetSystemMetrics(SM_CYSMICON); 00934 hMemDC = CreateCompatibleDC(hdc); 00935 hBitmap = CreateCompatibleBitmap(hdc, cx, cy); 00936 hOldBitmap = SelectObject(hMemDC, hBitmap); 00937 SetMapMode(hMemDC, MM_TEXT); 00938 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU)); 00939 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL); 00940 SelectObject (hMemDC, hOldBitmap); 00941 DeleteObject(hBrush); 00942 DeleteDC(hMemDC); 00943 ReleaseDC(hChild, hdc); 00944 hSysMenuBitmap = hBitmap; 00945 } 00946 } 00947 00948 if( !InsertMenuA(menu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP, 00949 (UINT_PTR)hSysPopup, (LPSTR)hSysMenuBitmap)) 00950 { 00951 TRACE("not inserted\n"); 00952 DestroyMenu(hSysPopup); 00953 return 0; 00954 } 00955 00956 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED); 00957 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED); 00958 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED); 00959 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE); 00960 00961 /* redraw menu */ 00962 DrawMenuBar(frame); 00963 00964 return 1; 00965 } 00966 00967 /********************************************************************** 00968 * MDI_RestoreFrameMenu 00969 */ 00970 static BOOL MDI_RestoreFrameMenu( HWND frame, HWND hChild, HBITMAP hBmpClose ) 00971 { 00972 MENUITEMINFOW menuInfo; 00973 HMENU menu = GetMenu( frame ); 00974 INT nItems; 00975 UINT iId; 00976 00977 TRACE("frame %p,child %p\n",frame, hChild); 00978 00979 if( !menu ) return 0; 00980 00981 /* if there is no system buttons then nothing to do */ 00982 nItems = GetMenuItemCount(menu) - 1; 00983 iId = GetMenuItemID(menu,nItems) ; 00984 if( !(iId == SC_RESTORE || iId == SC_CLOSE) ) 00985 return 0; 00986 00987 /* 00988 * Remove the system menu, If that menu is the icon of the window 00989 * as it is in win95, we have to delete the bitmap. 00990 */ 00991 memset(&menuInfo, 0, sizeof(menuInfo)); 00992 menuInfo.cbSize = sizeof(menuInfo); 00993 menuInfo.fMask = MIIM_DATA | MIIM_TYPE | MIIM_BITMAP; 00994 00995 GetMenuItemInfoW(menu, 00996 0, 00997 TRUE, 00998 &menuInfo); 00999 01000 RemoveMenu(menu,0,MF_BYPOSITION); 01001 01002 if ( (menuInfo.fType & MFT_BITMAP) && 01003 (menuInfo.dwTypeData != 0) && 01004 (menuInfo.dwTypeData != (LPWSTR)hBmpClose) ) 01005 { 01006 DeleteObject(menuInfo.dwTypeData); 01007 } 01008 01009 if ( menuInfo.hbmpItem != 0 ) 01010 DeleteObject(menuInfo.hbmpItem); 01011 01012 /* close */ 01013 DeleteMenu(menu, SC_CLOSE, MF_BYCOMMAND); 01014 /* restore */ 01015 DeleteMenu(menu, SC_RESTORE, MF_BYCOMMAND); 01016 /* minimize */ 01017 DeleteMenu(menu, SC_MINIMIZE, MF_BYCOMMAND); 01018 01019 DrawMenuBar(frame); 01020 01021 return 1; 01022 } 01023 01024 01025 /********************************************************************** 01026 * MDI_UpdateFrameText 01027 * 01028 * used when child window is maximized/restored 01029 * 01030 * Note: lpTitle can be NULL 01031 */ 01032 static void MDI_UpdateFrameText( HWND frame, HWND hClient, BOOL repaint, LPCWSTR lpTitle ) 01033 { 01034 WCHAR lpBuffer[MDI_MAXTITLELENGTH+1]; 01035 MDICLIENTINFO *ci = get_client_info( hClient ); 01036 01037 TRACE("frameText %s\n", debugstr_w(lpTitle)); 01038 01039 if (!ci) return; 01040 01041 if (!lpTitle && !ci->frameTitle) /* first time around, get title from the frame window */ 01042 { 01043 GetWindowTextW( frame, lpBuffer, sizeof(lpBuffer)/sizeof(WCHAR) ); 01044 lpTitle = lpBuffer; 01045 } 01046 01047 /* store new "default" title if lpTitle is not NULL */ 01048 if (lpTitle) 01049 { 01050 HeapFree( GetProcessHeap(), 0, ci->frameTitle ); 01051 if ((ci->frameTitle = HeapAlloc( GetProcessHeap(), 0, (strlenW(lpTitle)+1)*sizeof(WCHAR)))) 01052 strcpyW( ci->frameTitle, lpTitle ); 01053 } 01054 01055 if (ci->frameTitle) 01056 { 01057 if (ci->hwndChildMaximized) 01058 { 01059 /* combine frame title and child title if possible */ 01060 01061 static const WCHAR lpBracket[] = {' ','-',' ','[',0}; 01062 static const WCHAR lpBracket2[] = {']',0}; 01063 int i_frame_text_length = strlenW(ci->frameTitle); 01064 01065 lstrcpynW( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH); 01066 01067 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH ) 01068 { 01069 strcatW( lpBuffer, lpBracket ); 01070 if (GetWindowTextW( ci->hwndActiveChild, lpBuffer + i_frame_text_length + 4, 01071 MDI_MAXTITLELENGTH - i_frame_text_length - 5 )) 01072 strcatW( lpBuffer, lpBracket2 ); 01073 else 01074 lpBuffer[i_frame_text_length] = 0; /* remove bracket */ 01075 } 01076 } 01077 else 01078 { 01079 lstrcpynW(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 ); 01080 } 01081 } 01082 else 01083 lpBuffer[0] = '\0'; 01084 01085 DefWindowProcW( frame, WM_SETTEXT, 0, (LPARAM)lpBuffer ); 01086 01087 if (repaint) 01088 SetWindowPos( frame, 0,0,0,0,0, SWP_FRAMECHANGED | 01089 SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER ); 01090 } 01091 01092 01093 /* ----------------------------- Interface ---------------------------- */ 01094 01095 01096 /********************************************************************** 01097 * MDIClientWndProc_common 01098 */ 01099 LRESULT WINAPI MDIClientWndProc_common( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, BOOL unicode ) 01100 { 01101 MDICLIENTINFO *ci = NULL; 01102 01103 TRACE("%p %04x (%s) %08lx %08lx\n", hwnd, message, SPY_GetMsgName(message, hwnd), wParam, lParam); 01104 01105 if (!(ci = get_client_info(hwnd))) 01106 { 01107 if (message == WM_NCCREATE) 01108 { 01109 #ifdef __REACTOS__ 01110 if (!(ci = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ci)))) 01111 return FALSE; 01112 SetWindowLongPtrW( hwnd, 0, (LONG_PTR)ci ); 01113 ci->hBmpClose = 0; 01114 NtUserSetWindowFNID( hwnd, FNID_MDICLIENT); // wine uses WIN_ISMDICLIENT 01115 #else 01116 WND *wndPtr = WIN_GetPtr( hwnd ); 01117 wndPtr->flags |= WIN_ISMDICLIENT; 01118 WIN_ReleasePtr( wndPtr ); 01119 #endif 01120 } 01121 return unicode ? DefWindowProcW( hwnd, message, wParam, lParam ) : 01122 DefWindowProcA( hwnd, message, wParam, lParam ); 01123 } 01124 01125 switch (message) 01126 { 01127 case WM_CREATE: 01128 { 01129 /* Since we are using only cs->lpCreateParams, we can safely 01130 * cast to LPCREATESTRUCTA here */ 01131 LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam; 01132 LPCLIENTCREATESTRUCT ccs = (LPCLIENTCREATESTRUCT)cs->lpCreateParams; 01133 01134 ci->hWindowMenu = ccs->hWindowMenu; 01135 ci->idFirstChild = ccs->idFirstChild; 01136 ci->hwndChildMaximized = 0; 01137 ci->child = NULL; 01138 ci->nActiveChildren = 0; 01139 ci->nTotalCreated = 0; 01140 ci->frameTitle = NULL; 01141 ci->mdiFlags = 0; 01142 ci->hFrameMenu = GetMenu(cs->hwndParent); 01143 01144 if (!ci->hBmpClose) ci->hBmpClose = CreateMDIMenuBitmap(); 01145 01146 TRACE("Client created: hwnd %p, Window menu %p, idFirst = %04x\n", 01147 hwnd, ci->hWindowMenu, ci->idFirstChild ); 01148 return 0; 01149 } 01150 01151 case WM_DESTROY: 01152 { 01153 if( ci->hwndChildMaximized ) 01154 MDI_RestoreFrameMenu(GetParent(hwnd), ci->hwndChildMaximized, ci->hBmpClose); 01155 01156 ci->nActiveChildren = 0; 01157 MDI_RefreshMenu(ci); 01158 01159 HeapFree( GetProcessHeap(), 0, ci->child ); 01160 HeapFree( GetProcessHeap(), 0, ci->frameTitle ); 01161 #ifdef __REACTOS__ 01162 HeapFree( GetProcessHeap(), 0, ci ); 01163 SetWindowLongPtrW( hwnd, 0, 0 ); 01164 #endif 01165 return 0; 01166 } 01167 01168 #ifdef __REACTOS__ 01169 case WM_NCDESTROY: 01170 { 01171 NtUserSetWindowFNID(hwnd, FNID_DESTROY); 01172 return 0; 01173 } 01174 #endif 01175 01176 case WM_MDIACTIVATE: 01177 { 01178 if( ci->hwndActiveChild != (HWND)wParam ) 01179 SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE); 01180 return 0; 01181 } 01182 01183 case WM_MDICASCADE: 01184 return MDICascade(hwnd, ci); 01185 01186 case WM_MDICREATE: 01187 if (lParam) 01188 { 01189 HWND child; 01190 01191 if (unicode) 01192 { 01193 MDICREATESTRUCTW *csW = (MDICREATESTRUCTW *)lParam; 01194 child = CreateWindowExW(WS_EX_MDICHILD, csW->szClass, 01195 csW->szTitle, csW->style, 01196 csW->x, csW->y, csW->cx, csW->cy, 01197 hwnd, 0, csW->hOwner, 01198 (LPVOID)csW->lParam); 01199 } 01200 else 01201 { 01202 MDICREATESTRUCTA *csA = (MDICREATESTRUCTA *)lParam; 01203 child = CreateWindowExA(WS_EX_MDICHILD, csA->szClass, 01204 csA->szTitle, csA->style, 01205 csA->x, csA->y, csA->cx, csA->cy, 01206 hwnd, 0, csA->hOwner, 01207 (LPVOID)csA->lParam); 01208 } 01209 return (LRESULT)child; 01210 } 01211 return 0; 01212 01213 case WM_MDIDESTROY: 01214 return MDIDestroyChild( hwnd, ci, (HWND)wParam, TRUE ); 01215 01216 case WM_MDIGETACTIVE: 01217 if (lParam) *(BOOL *)lParam = IsZoomed(ci->hwndActiveChild); 01218 return (LRESULT)ci->hwndActiveChild; 01219 01220 case WM_MDIICONARRANGE: 01221 ci->mdiFlags |= MDIF_NEEDUPDATE; 01222 ArrangeIconicWindows( hwnd ); 01223 ci->sbRecalc = SB_BOTH+1; 01224 SendMessageW( hwnd, WM_MDICALCCHILDSCROLL, 0, 0 ); 01225 return 0; 01226 01227 case WM_MDIMAXIMIZE: 01228 ShowWindow( (HWND)wParam, SW_MAXIMIZE ); 01229 return 0; 01230 01231 case WM_MDINEXT: /* lParam != 0 means previous window */ 01232 { 01233 HWND next = MDI_GetWindow( ci, (HWND)wParam, !lParam, 0 ); 01234 MDI_SwitchActiveChild( ci, next, TRUE ); 01235 break; 01236 } 01237 01238 case WM_MDIRESTORE: 01239 ShowWindow( (HWND)wParam, SW_SHOWNORMAL ); 01240 return 0; 01241 01242 case WM_MDISETMENU: 01243 return MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam ); 01244 01245 case WM_MDIREFRESHMENU: 01246 return MDI_RefreshMenu( ci ); 01247 01248 case WM_MDITILE: 01249 ci->mdiFlags |= MDIF_NEEDUPDATE; 01250 ShowScrollBar( hwnd, SB_BOTH, FALSE ); 01251 MDITile( hwnd, ci, wParam ); 01252 ci->mdiFlags &= ~MDIF_NEEDUPDATE; 01253 return 0; 01254 01255 case WM_VSCROLL: 01256 case WM_HSCROLL: 01257 ci->mdiFlags |= MDIF_NEEDUPDATE; 01258 ScrollChildren( hwnd, message, wParam, lParam ); 01259 ci->mdiFlags &= ~MDIF_NEEDUPDATE; 01260 return 0; 01261 01262 case WM_SETFOCUS: 01263 if (ci->hwndActiveChild && !IsIconic( ci->hwndActiveChild )) 01264 SetFocus( ci->hwndActiveChild ); 01265 return 0; 01266 01267 case WM_NCACTIVATE: 01268 if( ci->hwndActiveChild ) 01269 SendMessageW(ci->hwndActiveChild, message, wParam, lParam); 01270 break; 01271 01272 case WM_PARENTNOTIFY: 01273 switch (LOWORD(wParam)) 01274 { 01275 case WM_CREATE: 01276 if (GetWindowLongPtrW((HWND)lParam, GWL_EXSTYLE) & WS_EX_MDICHILD) 01277 { 01278 // ReactOS See rev 33503 01279 if (!ci->child) 01280 ci->child = HeapAlloc(GetProcessHeap(), 0, sizeof(HWND)); 01281 else 01282 ci->child = HeapReAlloc(GetProcessHeap(), 0, ci->child, sizeof(HWND) * (ci->nActiveChildren + 1)); 01283 01284 TRACE("Adding MDI child %p, # of children %d\n", 01285 (HWND)lParam, ci->nActiveChildren); 01286 01287 if (ci->child != NULL) 01288 { 01289 ci->child[ci->nActiveChildren] = (HWND)lParam; 01290 ci->nTotalCreated++; 01291 ci->nActiveChildren++; 01292 } 01293 } 01294 break; 01295 01296 case WM_LBUTTONDOWN: 01297 { 01298 HWND child; 01299 POINT pt; 01300 pt.x = (short)LOWORD(lParam); 01301 pt.y = (short)HIWORD(lParam); 01302 child = ChildWindowFromPoint(hwnd, pt); 01303 01304 TRACE("notification from %p (%li,%li)\n",child,pt.x,pt.y); 01305 01306 if( child && child != hwnd && child != ci->hwndActiveChild ) 01307 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE ); 01308 break; 01309 } 01310 01311 case WM_DESTROY: 01312 return MDIDestroyChild( hwnd, ci, WIN_GetFullHandle( (HWND)lParam ), FALSE ); 01313 } 01314 return 0; 01315 01316 case WM_SIZE: 01317 if( ci->hwndActiveChild && IsZoomed(ci->hwndActiveChild) ) 01318 { 01319 RECT rect; 01320 01321 rect.left = 0; 01322 rect.top = 0; 01323 rect.right = LOWORD(lParam); 01324 rect.bottom = HIWORD(lParam); 01325 AdjustWindowRectEx(&rect, GetWindowLongPtrA(ci->hwndActiveChild, GWL_STYLE), 01326 0, GetWindowLongPtrA(ci->hwndActiveChild, GWL_EXSTYLE) ); 01327 MoveWindow(ci->hwndActiveChild, rect.left, rect.top, 01328 rect.right - rect.left, rect.bottom - rect.top, 1); 01329 } 01330 else 01331 MDI_PostUpdate(hwnd, ci, SB_BOTH+1); 01332 01333 break; 01334 01335 case WM_MDICALCCHILDSCROLL: 01336 if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc ) 01337 { 01338 CalcChildScroll(hwnd, ci->sbRecalc-1); 01339 ci->sbRecalc = 0; 01340 ci->mdiFlags &= ~MDIF_NEEDUPDATE; 01341 } 01342 return 0; 01343 } 01344 return unicode ? DefWindowProcW( hwnd, message, wParam, lParam ) : 01345 DefWindowProcA( hwnd, message, wParam, lParam ); 01346 } 01347 01348 /*********************************************************************** 01349 * MDIClientWndProcA 01350 */ 01351 LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) 01352 { 01353 if (!IsWindow(hwnd)) return 0; 01354 return MDIClientWndProc_common( hwnd, message, wParam, lParam, FALSE ); 01355 } 01356 01357 /*********************************************************************** 01358 * MDIClientWndProcW 01359 */ 01360 LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) 01361 { 01362 if (!IsWindow(hwnd)) return 0; 01363 return MDIClientWndProc_common( hwnd, message, wParam, lParam, TRUE ); 01364 } 01365 01366 /*********************************************************************** 01367 * DefFrameProcA (USER32.@) 01368 */ 01369 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient, 01370 UINT message, WPARAM wParam, LPARAM lParam) 01371 { 01372 if (hwndMDIClient) 01373 { 01374 switch (message) 01375 { 01376 case WM_SETTEXT: 01377 { 01378 DWORD len = MultiByteToWideChar( CP_ACP, 0, (LPSTR)lParam, -1, NULL, 0 ); 01379 LPWSTR text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); 01380 if (text == NULL) 01381 return 0; 01382 MultiByteToWideChar( CP_ACP, 0, (LPSTR)lParam, -1, text, len ); 01383 MDI_UpdateFrameText( hwnd, hwndMDIClient, FALSE, text ); 01384 HeapFree( GetProcessHeap(), 0, text ); 01385 } 01386 return 1; /* success. FIXME: check text length */ 01387 01388 case WM_COMMAND: 01389 case WM_NCACTIVATE: 01390 case WM_NEXTMENU: 01391 case WM_SETFOCUS: 01392 case WM_SIZE: 01393 return DefFrameProcW( hwnd, hwndMDIClient, message, wParam, lParam ); 01394 } 01395 } 01396 return DefWindowProcA(hwnd, message, wParam, lParam); 01397 } 01398 01399 01400 /*********************************************************************** 01401 * DefFrameProcW (USER32.@) 01402 */ 01403 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient, 01404 UINT message, WPARAM wParam, LPARAM lParam) 01405 { 01406 MDICLIENTINFO *ci = get_client_info( hwndMDIClient ); 01407 01408 TRACE("%p %p %04x (%s) %08lx %08lx\n", hwnd, hwndMDIClient, message, SPY_GetMsgName(message, hwnd), wParam, lParam); 01409 01410 if (ci) 01411 { 01412 switch (message) 01413 { 01414 case WM_COMMAND: 01415 { 01416 WORD id = LOWORD(wParam); 01417 /* check for possible syscommands for maximized MDI child */ 01418 if (id < ci->idFirstChild || id >= ci->idFirstChild + ci->nActiveChildren) 01419 { 01420 if( (id - 0xf000) & 0xf00f ) break; 01421 if( !ci->hwndChildMaximized ) break; 01422 switch( id ) 01423 { 01424 case SC_CLOSE: 01425 if (!is_close_enabled(ci->hwndActiveChild, 0)) break; 01426 case SC_SIZE: 01427 case SC_MOVE: 01428 case SC_MINIMIZE: 01429 case SC_MAXIMIZE: 01430 case SC_NEXTWINDOW: 01431 case SC_PREVWINDOW: 01432 case SC_RESTORE: 01433 return SendMessageW( ci->hwndActiveChild, WM_SYSCOMMAND, 01434 wParam, lParam); 01435 } 01436 } 01437 else 01438 { 01439 HWND childHwnd; 01440 if (id - ci->idFirstChild == MDI_MOREWINDOWSLIMIT) 01441 /* User chose "More Windows..." */ 01442 childHwnd = MDI_MoreWindowsDialog(hwndMDIClient); 01443 else 01444 /* User chose one of the windows listed in the "Windows" menu */ 01445 childHwnd = MDI_GetChildByID(hwndMDIClient, id, ci); 01446 01447 if( childHwnd ) 01448 SendMessageW( hwndMDIClient, WM_MDIACTIVATE, (WPARAM)childHwnd, 0 ); 01449 } 01450 } 01451 break; 01452 01453 case WM_NCACTIVATE: 01454 SendMessageW(hwndMDIClient, message, wParam, lParam); 01455 break; 01456 01457 case WM_SETTEXT: 01458 MDI_UpdateFrameText( hwnd, hwndMDIClient, FALSE, (LPWSTR)lParam ); 01459 return 1; /* success. FIXME: check text length */ 01460 01461 case WM_SETFOCUS: 01462 SetFocus(hwndMDIClient); 01463 break; 01464 01465 case WM_SIZE: 01466 MoveWindow(hwndMDIClient, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); 01467 break; 01468 01469 case WM_NEXTMENU: 01470 { 01471 MDINEXTMENU *next_menu = (MDINEXTMENU *)lParam; 01472 01473 if (!IsIconic(hwnd) && ci->hwndActiveChild && !IsZoomed(ci->hwndActiveChild)) 01474 { 01475 /* control menu is between the frame system menu and 01476 * the first entry of menu bar */ 01477 // WND *wndPtr = WIN_GetPtr(hwnd); 01478 01479 if( (wParam == VK_LEFT && GetMenu(hwnd) == next_menu->hmenuIn) || 01480 (wParam == VK_RIGHT && GetSubMenu(GetMenu(hwnd), 0) == next_menu->hmenuIn) ) 01481 { 01482 // WIN_ReleasePtr(wndPtr); 01483 // wndPtr = WIN_GetPtr(ci->hwndActiveChild); 01484 next_menu->hmenuNext = GetSubMenu(GetMenu(ci->hwndActiveChild), 0); 01485 next_menu->hwndNext = ci->hwndActiveChild; 01486 } 01487 // WIN_ReleasePtr(wndPtr); 01488 } 01489 return 0; 01490 } 01491 } 01492 } 01493 01494 return DefWindowProcW( hwnd, message, wParam, lParam ); 01495 } 01496 01497 /*********************************************************************** 01498 * DefMDIChildProcA (USER32.@) 01499 */ 01500 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message, 01501 WPARAM wParam, LPARAM lParam ) 01502 { 01503 HWND client = GetParent(hwnd); 01504 MDICLIENTINFO *ci = get_client_info( client ); 01505 01506 TRACE("%p %04x (%s) %08lx %08lx\n", hwnd, message, SPY_GetMsgName(message, hwnd), wParam, lParam); 01507 hwnd = WIN_GetFullHandle( hwnd ); 01508 if (!ci) return DefWindowProcA( hwnd, message, wParam, lParam ); 01509 01510 switch (message) 01511 { 01512 case WM_SETTEXT: 01513 DefWindowProcA(hwnd, message, wParam, lParam); 01514 if( ci->hwndChildMaximized == hwnd ) 01515 MDI_UpdateFrameText( GetParent(client), client, TRUE, NULL ); 01516 return 1; /* success. FIXME: check text length */ 01517 01518 case WM_GETMINMAXINFO: 01519 case WM_MENUCHAR: 01520 case WM_CLOSE: 01521 case WM_SETFOCUS: 01522 case WM_CHILDACTIVATE: 01523 case WM_SYSCOMMAND: 01524 case WM_SHOWWINDOW: 01525 #ifndef __REACTOS__ 01526 case WM_SETVISIBLE: 01527 #endif 01528 case WM_SIZE: 01529 case WM_NEXTMENU: 01530 case WM_SYSCHAR: 01531 case WM_DESTROY: 01532 return DefMDIChildProcW( hwnd, message, wParam, lParam ); 01533 } 01534 return DefWindowProcA(hwnd, message, wParam, lParam); 01535 } 01536 01537 01538 /*********************************************************************** 01539 * DefMDIChildProcW (USER32.@) 01540 */ 01541 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message, 01542 WPARAM wParam, LPARAM lParam ) 01543 { 01544 HWND client = GetParent(hwnd); 01545 MDICLIENTINFO *ci = get_client_info( client ); 01546 01547 TRACE("%p %04x (%s) %08lx %08lx\n", hwnd, message, SPY_GetMsgName(message, hwnd), wParam, lParam); 01548 01549 hwnd = WIN_GetFullHandle( hwnd ); 01550 if (!ci) return DefWindowProcW( hwnd, message, wParam, lParam ); 01551 01552 switch (message) 01553 { 01554 case WM_SETTEXT: 01555 DefWindowProcW(hwnd, message, wParam, lParam); 01556 if( ci->hwndChildMaximized == hwnd ) 01557 MDI_UpdateFrameText( GetParent(client), client, TRUE, NULL ); 01558 return 1; /* success. FIXME: check text length */ 01559 01560 case WM_GETMINMAXINFO: 01561 MDI_ChildGetMinMaxInfo( client, hwnd, (MINMAXINFO *)lParam ); 01562 return 0; 01563 01564 case WM_MENUCHAR: 01565 return 0x00010000; /* MDI children don't have menu bars */ 01566 01567 case WM_CLOSE: 01568 SendMessageW( client, WM_MDIDESTROY, (WPARAM)hwnd, 0 ); 01569 return 0; 01570 01571 case WM_SETFOCUS: 01572 if (ci->hwndActiveChild != hwnd) 01573 MDI_ChildActivate( client, hwnd ); 01574 break; 01575 01576 case WM_CHILDACTIVATE: 01577 MDI_ChildActivate( client, hwnd ); 01578 return 0; 01579 01580 case WM_SYSCOMMAND: 01581 switch( wParam & 0xfff0) 01582 { 01583 case SC_MOVE: 01584 if( ci->hwndChildMaximized == hwnd ) 01585 return 0; 01586 break; 01587 case SC_RESTORE: 01588 case SC_MINIMIZE: 01589 break; 01590 case SC_MAXIMIZE: 01591 if (ci->hwndChildMaximized == hwnd ) 01592 return SendMessageW( GetParent(client), message, wParam, lParam); 01593 break; 01594 case SC_NEXTWINDOW: 01595 SendMessageW( client, WM_MDINEXT, 0, 0); 01596 return 0; 01597 case SC_PREVWINDOW: 01598 SendMessageW( client, WM_MDINEXT, 0, 1); 01599 return 0; 01600 } 01601 break; 01602 01603 case WM_SHOWWINDOW: 01604 #ifndef __REACTOS__ 01605 case WM_SETVISIBLE: 01606 #endif 01607 if (ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE; 01608 else MDI_PostUpdate(client, ci, SB_BOTH+1); 01609 break; 01610 01611 case WM_SIZE: 01612 /* This is the only place where we switch to/from maximized state */ 01613 /* do not change */ 01614 TRACE("current active %p, maximized %p\n", ci->hwndActiveChild, ci->hwndChildMaximized); 01615 01616 if( ci->hwndChildMaximized == hwnd && wParam != SIZE_MAXIMIZED) 01617 { 01618 HWND frame; 01619 01620 ci->hwndChildMaximized = 0; 01621 01622 frame = GetParent(client); 01623 MDI_RestoreFrameMenu( frame, hwnd, ci->hBmpClose ); 01624 MDI_UpdateFrameText( frame, client, TRUE, NULL ); 01625 } 01626 01627 if( wParam == SIZE_MAXIMIZED ) 01628 { 01629 HWND frame, hMaxChild = ci->hwndChildMaximized; 01630 01631 if( hMaxChild == hwnd ) break; 01632 01633 if( hMaxChild) 01634 { 01635 SendMessageW( hMaxChild, WM_SETREDRAW, FALSE, 0 ); 01636 01637 MDI_RestoreFrameMenu( GetParent(client), hMaxChild, ci->hBmpClose ); 01638 ShowWindow( hMaxChild, SW_SHOWNOACTIVATE ); 01639 01640 SendMessageW( hMaxChild, WM_SETREDRAW, TRUE, 0 ); 01641 } 01642 01643 TRACE("maximizing child %p\n", hwnd ); 01644 01645 /* keep track of the maximized window. */ 01646 ci->hwndChildMaximized = hwnd; /* !!! */ 01647 01648 frame = GetParent(client); 01649 MDI_AugmentFrameMenu( frame, hwnd ); 01650 MDI_UpdateFrameText( frame, client, TRUE, NULL ); 01651 } 01652 01653 if( wParam == SIZE_MINIMIZED ) 01654 { 01655 HWND switchTo = MDI_GetWindow( ci, hwnd, TRUE, WS_MINIMIZE ); 01656 01657 if (!switchTo) switchTo = hwnd; 01658 SendMessageW( switchTo, WM_CHILDACTIVATE, 0, 0 ); 01659 } 01660 01661 MDI_PostUpdate(client, ci, SB_BOTH+1); 01662 break; 01663 01664 case WM_NEXTMENU: 01665 { 01666 MDINEXTMENU *next_menu = (MDINEXTMENU *)lParam; 01667 HWND parent = GetParent(client); 01668 01669 if( wParam == VK_LEFT ) /* switch to frame system menu */ 01670 { 01671 // WND *wndPtr = WIN_GetPtr( parent ); 01672 next_menu->hmenuNext = GetSubMenu( GetMenu(parent), 0 ); 01673 // WIN_ReleasePtr( wndPtr ); 01674 } 01675 if( wParam == VK_RIGHT ) /* to frame menu bar */ 01676 { 01677 next_menu->hmenuNext = GetMenu(parent); 01678 } 01679 next_menu->hwndNext = parent; 01680 return 0; 01681 } 01682 01683 case WM_SYSCHAR: 01684 if (wParam == '-') 01685 { 01686 SendMessageW( hwnd, WM_SYSCOMMAND, SC_KEYMENU, VK_SPACE); 01687 return 0; 01688 } 01689 break; 01690 01691 case WM_DESTROY: 01692 /* Remove itself from the Window menu */ 01693 MDI_RefreshMenu(ci); 01694 break; 01695 } 01696 return DefWindowProcW(hwnd, message, wParam, lParam); 01697 } 01698 01699 /********************************************************************** 01700 * CreateMDIWindowA (USER32.@) Creates a MDI child 01701 * 01702 * RETURNS 01703 * Success: Handle to created window 01704 * Failure: NULL 01705 */ 01706 HWND WINAPI CreateMDIWindowA( 01707 LPCSTR lpClassName, /* [in] Pointer to registered child class name */ 01708 LPCSTR lpWindowName, /* [in] Pointer to window name */ 01709 DWORD dwStyle, /* [in] Window style */ 01710 INT X, /* [in] Horizontal position of window */ 01711 INT Y, /* [in] Vertical position of window */ 01712 INT nWidth, /* [in] Width of window */ 01713 INT nHeight, /* [in] Height of window */ 01714 HWND hWndParent, /* [in] Handle to parent window */ 01715 HINSTANCE hInstance, /* [in] Handle to application instance */ 01716 LPARAM lParam) /* [in] Application-defined value */ 01717 { 01718 TRACE("(%s,%s,%08lx,%d,%d,%d,%d,%p,%p,%08lx)\n", 01719 debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y, 01720 nWidth,nHeight,hWndParent,hInstance,lParam); 01721 01722 return CreateWindowExA(WS_EX_MDICHILD, lpClassName, lpWindowName, 01723 dwStyle, X, Y, nWidth, nHeight, hWndParent, 01724 0, hInstance, (LPVOID)lParam); 01725 } 01726 01727 /*********************************************************************** 01728 * CreateMDIWindowW (USER32.@) Creates a MDI child 01729 * 01730 * RETURNS 01731 * Success: Handle to created window 01732 * Failure: NULL 01733 */ 01734 HWND WINAPI CreateMDIWindowW( 01735 LPCWSTR lpClassName, /* [in] Pointer to registered child class name */ 01736 LPCWSTR lpWindowName, /* [in] Pointer to window name */ 01737 DWORD dwStyle, /* [in] Window style */ 01738 INT X, /* [in] Horizontal position of window */ 01739 INT Y, /* [in] Vertical position of window */ 01740 INT nWidth, /* [in] Width of window */ 01741 INT nHeight, /* [in] Height of window */ 01742 HWND hWndParent, /* [in] Handle to parent window */ 01743 HINSTANCE hInstance, /* [in] Handle to application instance */ 01744 LPARAM lParam) /* [in] Application-defined value */ 01745 { 01746 TRACE("(%s,%s,%08lx,%d,%d,%d,%d,%p,%p,%08lx)\n", 01747 debugstr_w(lpClassName), debugstr_w(lpWindowName), dwStyle, X, Y, 01748 nWidth, nHeight, hWndParent, hInstance, lParam); 01749 01750 return CreateWindowExW(WS_EX_MDICHILD, lpClassName, lpWindowName, 01751 dwStyle, X, Y, nWidth, nHeight, hWndParent, 01752 0, hInstance, (LPVOID)lParam); 01753 } 01754 01755 /********************************************************************** 01756 * TranslateMDISysAccel (USER32.@) 01757 */ 01758 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg ) 01759 { 01760 if (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN) 01761 { 01762 MDICLIENTINFO *ci = get_client_info( hwndClient ); 01763 WPARAM wParam = 0; 01764 01765 if (!ci || !IsWindowEnabled(ci->hwndActiveChild)) return 0; 01766 01767 /* translate if the Ctrl key is down and Alt not. */ 01768 01769 if( (GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_MENU) & 0x8000)) 01770 { 01771 switch( msg->wParam ) 01772 { 01773 case VK_F6: 01774 case VK_TAB: 01775 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 ) ? SC_NEXTWINDOW : SC_PREVWINDOW; 01776 break; 01777 case VK_F4: 01778 case VK_RBUTTON: 01779 if (is_close_enabled(ci->hwndActiveChild, 0)) 01780 { 01781 wParam = SC_CLOSE; 01782 break; 01783 } 01784 /* fall through */ 01785 default: 01786 return 0; 01787 } 01788 TRACE("wParam = %04lx\n", wParam); 01789 SendMessageW(ci->hwndActiveChild, WM_SYSCOMMAND, wParam, msg->wParam); 01790 return 1; 01791 } 01792 } 01793 return 0; /* failure */ 01794 } 01795 01796 /*********************************************************************** 01797 * CalcChildScroll (USER32.@) 01798 */ 01799 void WINAPI CalcChildScroll( HWND hwnd, INT scroll ) 01800 { 01801 SCROLLINFO info; 01802 RECT childRect, clientRect; 01803 HWND *list; 01804 WINDOWINFO WindowInfo; 01805 01806 GetClientRect( hwnd, &clientRect ); 01807 SetRectEmpty( &childRect ); 01808 01809 /* The rectangle returned by GetClientRect always has 0,0 as top left 01810 * because it is in client coordinates. The rectangles returned by 01811 * GetWindowRect are in screen coordinates to make this complicated. 01812 * 01813 * Apparently (in ReactOS at least) the rcClient returned by GetWindowInfo 01814 * is in screen coordinates too. 01815 */ 01816 WindowInfo.cbSize = sizeof(WindowInfo); 01817 if (!GetWindowInfo(hwnd, &WindowInfo)) 01818 { 01819 ERR("Can't get window info\n"); 01820 return; 01821 } 01822 01823 if ((list = WIN_ListChildren( hwnd ))) 01824 { 01825 int i; 01826 for (i = 0; list[i]; i++) 01827 { 01828 DWORD style = GetWindowLongPtrW( list[i], GWL_STYLE ); 01829 if (style & WS_MAXIMIZE) 01830 { 01831 HeapFree( GetProcessHeap(), 0, list ); 01832 ShowScrollBar( hwnd, SB_BOTH, FALSE ); 01833 return; 01834 } 01835 if (style & WS_VISIBLE) 01836 { 01837 RECT rect; 01838 GetWindowRect( list[i], &rect ); 01839 OffsetRect(&rect, -WindowInfo.rcClient.left, 01840 -WindowInfo.rcClient.top); 01841 UnionRect( &childRect, &rect, &childRect ); 01842 } 01843 } 01844 HeapFree( GetProcessHeap(), 0, list ); 01845 } 01846 MapWindowPoints( 0, hwnd, (POINT *)&childRect, 2 ); 01847 UnionRect( &childRect, &clientRect, &childRect ); 01848 01849 /* set common info values */ 01850 info.cbSize = sizeof(info); 01851 info.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; 01852 01853 /* set the specific */ 01854 /* Note how we set nPos to 0 because we scroll the clients instead of 01855 * the window, and we set nPage to 1 bigger than the clientRect because 01856 * otherwise the scrollbar never disables. This causes a somewhat ugly 01857 * effect though while scrolling. 01858 */ 01859 switch( scroll ) 01860 { 01861 case SB_BOTH: 01862 case SB_HORZ: 01863 info.nMin = childRect.left; 01864 info.nMax = childRect.right; 01865 info.nPos = 0; 01866 info.nPage = 1 + clientRect.right - clientRect.left; 01867 SetScrollInfo(hwnd, SB_HORZ, &info, TRUE); 01868 if (scroll == SB_HORZ) break; 01869 /* fall through */ 01870 case SB_VERT: 01871 info.nMin = childRect.top; 01872 info.nMax = childRect.bottom; 01873 info.nPos = 0; 01874 info.nPage = 1 + clientRect.bottom - clientRect.top; 01875 SetScrollInfo(hwnd, SB_VERT, &info, TRUE); 01876 break; 01877 } 01878 } 01879 01880 01881 /*********************************************************************** 01882 * ScrollChildren (USER32.@) 01883 */ 01884 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam, 01885 LPARAM lParam) 01886 { 01887 INT newPos = -1; 01888 INT curPos, length, minPos, maxPos, shift; 01889 RECT rect; 01890 01891 GetClientRect( hWnd, &rect ); 01892 01893 switch(uMsg) 01894 { 01895 case WM_HSCROLL: 01896 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos); 01897 curPos = GetScrollPos(hWnd,SB_HORZ); 01898 length = (rect.right - rect.left) / 2; 01899 shift = GetSystemMetrics(SM_CYHSCROLL); 01900 break; 01901 case WM_VSCROLL: 01902 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos); 01903 curPos = GetScrollPos(hWnd,SB_VERT); 01904 length = (rect.bottom - rect.top) / 2; 01905 shift = GetSystemMetrics(SM_CXVSCROLL); 01906 break; 01907 default: 01908 return; 01909 } 01910 01911 switch( wParam ) 01912 { 01913 case SB_LINEUP: 01914 newPos = curPos - shift; 01915 break; 01916 case SB_LINEDOWN: 01917 newPos = curPos + shift; 01918 break; 01919 case SB_PAGEUP: 01920 newPos = curPos - length; 01921 break; 01922 case SB_PAGEDOWN: 01923 newPos = curPos + length; 01924 break; 01925 01926 case SB_THUMBPOSITION: 01927 newPos = LOWORD(lParam); 01928 break; 01929 01930 case SB_THUMBTRACK: 01931 return; 01932 01933 case SB_TOP: 01934 newPos = minPos; 01935 break; 01936 case SB_BOTTOM: 01937 newPos = maxPos; 01938 break; 01939 case SB_ENDSCROLL: 01940 CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ); 01941 return; 01942 } 01943 01944 if( newPos > maxPos ) 01945 newPos = maxPos; 01946 else 01947 if( newPos < minPos ) 01948 newPos = minPos; 01949 01950 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE); 01951 01952 if( uMsg == WM_VSCROLL ) 01953 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL, 01954 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); 01955 else 01956 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL, 01957 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN ); 01958 } 01959 01960 01961 /****************************************************************************** 01962 * CascadeWindows (USER32.@) Cascades MDI child windows 01963 * 01964 * RETURNS 01965 * Success: Number of cascaded windows. 01966 * Failure: 0 01967 */ 01968 WORD WINAPI 01969 CascadeWindows (HWND hwndParent, UINT wFlags, LPCRECT lpRect, 01970 UINT cKids, const HWND *lpKids) 01971 { 01972 FIXME("(%p,0x%08x,...,%u,...): stub\n", hwndParent, wFlags, cKids); 01973 return 0; 01974 } 01975 01976 /*********************************************************************** 01977 * CascadeChildWindows (USER32.@) 01978 */ 01979 WORD WINAPI CascadeChildWindows( HWND parent, UINT flags ) 01980 { 01981 return CascadeWindows( parent, flags, NULL, 0, NULL ); 01982 } 01983 01984 01985 /****************************************************************************** 01986 * TileWindows (USER32.@) Tiles MDI child windows 01987 * 01988 * RETURNS 01989 * Success: Number of tiled windows. 01990 * Failure: 0 01991 */ 01992 WORD WINAPI 01993 TileWindows (HWND hwndParent, UINT wFlags, LPCRECT lpRect, 01994 UINT cKids, const HWND *lpKids) 01995 { 01996 FIXME("(%p,0x%08x,...,%u,...): stub\n", hwndParent, wFlags, cKids); 01997 return 0; 01998 } 01999 02000 /*********************************************************************** 02001 * TileChildWindows (USER32.@) 02002 */ 02003 WORD WINAPI TileChildWindows( HWND parent, UINT flags ) 02004 { 02005 return TileWindows( parent, flags, NULL, 0, NULL ); 02006 } 02007 02008 02009 /************************************************************************ 02010 * "More Windows..." functionality 02011 */ 02012 02013 /* MDI_MoreWindowsDlgProc 02014 * 02015 * This function will process the messages sent to the "More Windows..." 02016 * dialog. 02017 * Return values: 0 = cancel pressed 02018 * HWND = ok pressed or double-click in the list... 02019 * 02020 */ 02021 02022 static INT_PTR WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam) 02023 { 02024 switch (iMsg) 02025 { 02026 case WM_INITDIALOG: 02027 { 02028 UINT widest = 0; 02029 UINT length; 02030 UINT i; 02031 MDICLIENTINFO *ci = get_client_info( (HWND)lParam ); 02032 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX); 02033 02034 for (i = 0; i < ci->nActiveChildren; i++) 02035 { 02036 WCHAR buffer[MDI_MAXTITLELENGTH]; 02037 02038 if (!InternalGetWindowText( ci->child[i], buffer, sizeof(buffer)/sizeof(WCHAR) )) 02039 continue; 02040 SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM)buffer ); 02041 SendMessageW(hListBox, LB_SETITEMDATA, i, (LPARAM)ci->child[i] ); 02042 length = strlenW(buffer); /* FIXME: should use GetTextExtentPoint */ 02043 if (length > widest) 02044 widest = length; 02045 } 02046 /* Make sure the horizontal scrollbar scrolls ok */ 02047 SendMessageW(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0); 02048 02049 /* Set the current selection */ 02050 SendMessageW(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0); 02051 return TRUE; 02052 } 02053 02054 case WM_COMMAND: 02055 switch (LOWORD(wParam)) 02056 { 02057 default: 02058 if (HIWORD(wParam) != LBN_DBLCLK) break; 02059 /* fall through */ 02060 case IDOK: 02061 { 02062 /* windows are sorted by menu ID, so we must return the 02063 * window associated to the given id 02064 */ 02065 HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX); 02066 UINT index = SendMessageW(hListBox, LB_GETCURSEL, 0, 0); 02067 LRESULT res = SendMessageW(hListBox, LB_GETITEMDATA, index, 0); 02068 EndDialog(hDlg, res); 02069 return TRUE; 02070 } 02071 case IDCANCEL: 02072 EndDialog(hDlg, 0); 02073 return TRUE; 02074 } 02075 break; 02076 } 02077 return FALSE; 02078 } 02079 02080 /* 02081 * 02082 * MDI_MoreWindowsDialog 02083 * 02084 * Prompts the user with a listbox containing the opened 02085 * documents. The user can then choose a windows and click 02086 * on OK to set the current window to the one selected, or 02087 * CANCEL to cancel. The function returns a handle to the 02088 * selected window. 02089 */ 02090 02091 static HWND MDI_MoreWindowsDialog(HWND hwnd) 02092 { 02093 LPCVOID template; 02094 HRSRC hRes; 02095 HANDLE hDlgTmpl; 02096 02097 hRes = FindResourceA(User32Instance, "MDI_MOREWINDOWS", (LPSTR)RT_DIALOG); 02098 02099 if (hRes == 0) 02100 return 0; 02101 02102 hDlgTmpl = LoadResource(User32Instance, hRes ); 02103 02104 if (hDlgTmpl == 0) 02105 return 0; 02106 02107 template = LockResource( hDlgTmpl ); 02108 02109 if (template == 0) 02110 return 0; 02111 02112 return (HWND) DialogBoxIndirectParamA(User32Instance, template, hwnd, 02113 MDI_MoreWindowsDlgProc, (LPARAM) hwnd); 02114 } Generated on Sun May 27 2012 04:38:43 for ReactOS by
1.7.6.1
|