ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

mdi.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.