Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

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  * Notes: Fairly complete implementation.
00010  *        Also, Excel and WinWord do _not_ use MDI so if you're trying
00011  *        to fix them look elsewhere. 
00012  *
00013  * Notes on how the "More Windows..." is implemented:
00014  *
00015  *      When we have more than 9 opened windows, a "More Windows..."
00016  *      option appears in the "Windows" menu. Each child window has
00017  *      a WND* associated with it, accesible via the children list of
00018  *      the parent window. This WND* has a wIDmenu member, which reflects
00019  *      the position of the child in the window list. For example, with
00020  *      9 child windows, we could have the following pattern:
00021  *
00022  *
00023  *
00024  *                Name of the child window    pWndChild->wIDmenu
00025  *                     Doc1                       5000
00026  *                     Doc2                       5001
00027  *                     Doc3                       5002
00028  *                     Doc4                       5003
00029  *                     Doc5                       5004
00030  *                     Doc6                       5005
00031  *                     Doc7                       5006
00032  *                     Doc8                       5007
00033  *                     Doc9                       5008
00034  *
00035  *
00036  *       The "Windows" menu, as the "More windows..." dialog, are constructed
00037  *       in this order. If we add a child, we would have the following list:
00038  *
00039  *
00040  *               Name of the child window    pWndChild->wIDmenu
00041  *                     Doc1                       5000
00042  *                     Doc2                       5001
00043  *                     Doc3                       5002
00044  *                     Doc4                       5003
00045  *                     Doc5                       5004
00046  *                     Doc6                       5005
00047  *                     Doc7                       5006
00048  *                     Doc8                       5007
00049  *                     Doc9                       5008
00050  *                     Doc10                      5009
00051  *
00052  *       But only 5000 to 5008 would be displayed in the "Windows" menu. We want
00053  *       the last created child to be in the menu, so we swap the last child with
00054  *       the 9th... Doc9 will be accessible via the "More Windows..." option.
00055  *
00056  *                     Doc1                       5000
00057  *                     Doc2                       5001
00058  *                     Doc3                       5002
00059  *                     Doc4                       5003
00060  *                     Doc5                       5004
00061  *                     Doc6                       5005
00062  *                     Doc7                       5006
00063  *                     Doc8                       5007
00064  *                     Doc9                       5009
00065  *                     Doc10                      5008
00066  *
00067  */
00068 
00069 #include <stdlib.h>
00070 #include <stdio.h>
00071 #include <string.h>
00072 #include <math.h>
00073 
00074 #include "windef.h"
00075 #include "winbase.h"
00076 #include "wingdi.h"
00077 #include "winuser.h"
00078 #include "wine/unicode.h"
00079 #include "win.h"
00080 #include "heap.h"
00081 #include "controls.h"
00082 #include "user.h"
00083 #ifndef __WIN32OS2__
00084 #include "nonclient.h"
00085 #include "struct32.h"
00086 #endif
00087 #include "debugtools.h"
00088 #include "dlgs.h"
00089 
00090 #ifdef __WIN32OS2__
00091 #include <heapstring.h>
00092 #define WIN_GetFullHandle(a)    a
00093 #endif
00094 
00095 DEFAULT_DEBUG_CHANNEL(mdi);
00096 
00097 #ifdef __WIN32OS2__
00098 #include "mdi.h"
00099 #include <win32wmisc.h>
00100 #else
00101 #define MDI_MAXLISTLENGTH       0x40
00102 #define MDI_MAXTITLELENGTH      0xa1
00103 
00104 #define MDI_NOFRAMEREPAINT      0
00105 #define MDI_REPAINTFRAMENOW     1
00106 #define MDI_REPAINTFRAME        2
00107 
00108 #define WM_MDICALCCHILDSCROLL   0x10ac /* this is exactly what Windows uses */
00109 
00110 /* "More Windows..." definitions */
00111 #define MDI_MOREWINDOWSLIMIT    9       /* after this number of windows, a "More Windows..." 
00112                                            option will appear under the Windows menu */
00113 #define MDI_IDC_LISTBOX         100
00114 #define MDI_IDS_MOREWINDOWS     13
00115 
00116 #define MDIF_NEEDUPDATE         0x0001
00117 
00118 typedef struct
00119 {
00120     UINT      nActiveChildren;
00121     HWND      hwndChildMaximized;
00122     HWND      hwndActiveChild;
00123     HMENU     hWindowMenu;
00124     UINT      idFirstChild;
00125     LPWSTR    frameTitle;
00126     UINT      nTotalCreated;
00127     UINT      mdiFlags;
00128     UINT      sbRecalc;   /* SB_xxx flags for scrollbar fixup */
00129 } MDICLIENTINFO;
00130 #endif
00131 
00132 static HBITMAP hBmpClose   = 0;
00133 static HBITMAP hBmpRestore = 0;
00134 
00135 /* ----------------- declarations ----------------- */
00136 static void MDI_UpdateFrameText( HWND, HWND, BOOL, LPCWSTR);
00137 static BOOL MDI_AugmentFrameMenu( HWND, HWND );
00138 static BOOL MDI_RestoreFrameMenu( HWND, HWND );
00139 static LONG MDI_ChildActivate( HWND, HWND );
00140 
00141 static HWND MDI_MoreWindowsDialog(HWND);
00142 static void MDI_SwapMenuItems(HWND, UINT, UINT);
00143 #ifdef __WIN32OS2__
00144        LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
00145        LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
00146 #else
00147 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
00148 static LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
00149 #endif
00150 
00151 /* -------- Miscellaneous service functions ----------
00152  *
00153  *                      MDI_GetChildByID
00154  */
00155 static HWND MDI_GetChildByID(HWND hwnd, UINT id)
00156 {
00157     HWND ret;
00158     HWND *win_array;
00159     int i;
00160 
00161     if (!(win_array = WIN_ListChildren( hwnd ))) return 0;
00162     for (i = 0; win_array[i]; i++)
00163     {
00164         if (GetWindowLongA( win_array[i], GWL_ID ) == id) break;
00165     }
00166     ret = win_array[i];
00167     HeapFree( GetProcessHeap(), 0, win_array );
00168     return ret;
00169 }
00170 
00171 static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
00172 {
00173     if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
00174     {
00175         ci->mdiFlags |= MDIF_NEEDUPDATE;
00176         PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
00177     }
00178     ci->sbRecalc = recalc;
00179 }
00180 
00181 
00182 #ifndef __WIN32OS2__
00183 /*********************************************************************
00184  * MDIClient class descriptor
00185  */
00186 const struct builtin_class_descr MDICLIENT_builtin_class =
00187 {
00188     "MDIClient",            /* name */
00189     CS_GLOBALCLASS,         /* style */
00190     MDIClientWndProcA,      /* procA */
00191     MDIClientWndProcW,      /* procW */
00192     sizeof(MDICLIENTINFO),  /* extra */
00193     IDC_ARROWA,             /* cursor */
00194     COLOR_APPWORKSPACE+1    /* brush */
00195 };
00196 
00197 static MDICLIENTINFO *get_client_info( HWND client )
00198 {
00199     MDICLIENTINFO *ret = NULL;
00200     WND *win = WIN_FindWndPtr( client );
00201     if (win)
00202     {
00203         if (win->cbWndExtra < sizeof(MDICLIENTINFO)) WARN( "%x is not an MDI client\n", client );
00204         else ret = (MDICLIENTINFO *)win->wExtra;
00205         WIN_ReleaseWndPtr( win );
00206     }
00207     return ret;
00208 }
00209 
00210 #endif
00211 
00212 /**********************************************************************
00213  *                      MDI_MenuModifyItem
00214  */
00215 static void MDI_MenuModifyItem( HWND client, HWND hWndChild )
00216 {
00217     MDICLIENTINFO *clientInfo = get_client_info( client );
00218     WCHAR buffer[128];
00219     UINT n, id;
00220 
00221     if (!clientInfo || !clientInfo->hWindowMenu) return;
00222 
00223     id = GetWindowLongA( hWndChild, GWL_ID );
00224     if (id >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT) return;
00225     buffer[0] = '&';
00226     buffer[1] = '1' + id - clientInfo->idFirstChild;
00227     buffer[2] = ' ';
00228     GetWindowTextW( hWndChild, buffer + 3, sizeof(buffer)/sizeof(WCHAR) - 3 );
00229 
00230     n = GetMenuState(clientInfo->hWindowMenu, id, MF_BYCOMMAND);
00231     ModifyMenuW(clientInfo->hWindowMenu, id, MF_BYCOMMAND | MF_STRING, id, buffer );
00232     CheckMenuItem(clientInfo->hWindowMenu, id, n & MF_CHECKED);
00233 }
00234 
00235 /**********************************************************************
00236  *                      MDI_MenuDeleteItem
00237  */
00238 static BOOL MDI_MenuDeleteItem( HWND client, HWND hWndChild )
00239 {
00240     WCHAR        buffer[128];
00241     static const WCHAR format[] = {'&','%','d',' ',0};
00242     MDICLIENTINFO *clientInfo = get_client_info( client );
00243     UINT         index      = 0,id,n;
00244 
00245     if( !clientInfo->nActiveChildren || !clientInfo->hWindowMenu )
00246         return FALSE;
00247 
00248     id = GetWindowLongA( hWndChild, GWL_ID );
00249     DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
00250 
00251  /* walk the rest of MDI children to prevent gaps in the id 
00252   * sequence and in the menu child list */
00253 
00254     for( index = id+1; index <= clientInfo->nActiveChildren + 
00255                                 clientInfo->idFirstChild; index++ )
00256     {
00257         HWND hwnd = MDI_GetChildByID(client,index);
00258         if (!hwnd)
00259         {
00260             TRACE("no window for id=%i\n",index);
00261             continue;
00262         }
00263 
00264         /* set correct id */
00265         SetWindowLongW( hwnd, GWL_ID, GetWindowLongW( hwnd, GWL_ID ) - 1 );
00266 
00267         n = wsprintfW(buffer, format ,index - clientInfo->idFirstChild);
00268         GetWindowTextW( hwnd, buffer + n, sizeof(buffer)/sizeof(WCHAR) - n );
00269 
00270         /*  change menu if the current child is to be shown in the 
00271          *  "Windows" menu
00272          */
00273         if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT) 
00274         ModifyMenuW(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
00275                       index - 1 , buffer ); 
00276     }
00277 
00278     /*  We must restore the "More Windows..." option if there are enough children
00279      */
00280     if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
00281     {
00282         WCHAR szTmp[50];
00283         LoadStringW(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, sizeof(szTmp)/sizeof(szTmp[0]));
00284         AppendMenuW(clientInfo->hWindowMenu, MF_STRING, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp);
00285     }
00286     return TRUE;
00287 }
00288 
00289 /**********************************************************************
00290  *                      MDI_GetWindow
00291  *
00292  * returns "activateable" child different from the current or zero
00293  */
00294 static HWND MDI_GetWindow(MDICLIENTINFO *clientInfo, HWND hWnd, BOOL bNext,
00295                             DWORD dwStyleMask )
00296 {
00297     int i;
00298     HWND *list;
00299     HWND last = 0;
00300 
00301     dwStyleMask |= WS_DISABLED | WS_VISIBLE;
00302     if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
00303 
00304     if (!(list = WIN_ListChildren( GetParent(hWnd) ))) return 0;
00305     i = 0;
00306     /* start from next after hWnd */
00307     while (list[i] && list[i] != hWnd) i++;
00308     if (list[i]) i++;
00309 
00310     for ( ; list[i]; i++)
00311     {
00312         if (GetWindow( list[i], GW_OWNER )) continue;
00313         if ((GetWindowLongW( list[i], GWL_STYLE ) & dwStyleMask) != WS_VISIBLE) continue;
00314         last = list[i];
00315         if (bNext) goto found;
00316     }
00317     /* now restart from the beginning */
00318     for (i = 0; list[i] && list[i] != hWnd; i++)
00319     {
00320         if (GetWindow( list[i], GW_OWNER )) continue;
00321         if ((GetWindowLongW( list[i], GWL_STYLE ) & dwStyleMask) != WS_VISIBLE) continue;
00322         last = list[i];
00323         if (bNext) goto found;
00324     }
00325  found:
00326     HeapFree( GetProcessHeap(), 0, list );
00327     return last;
00328 }
00329 
00330 /**********************************************************************
00331  *                      MDI_CalcDefaultChildPos
00332  *
00333  *  It seems that the default height is about 2/3 of the client rect
00334  */
00335 static void MDI_CalcDefaultChildPos( HWND hwnd, WORD n, LPPOINT lpPos, INT delta)
00336 {
00337     INT  nstagger;
00338     RECT rect;
00339     INT  spacing = GetSystemMetrics(SM_CYCAPTION) +
00340                      GetSystemMetrics(SM_CYFRAME) - 1; 
00341 
00342     GetClientRect( hwnd, &rect );
00343     if( rect.bottom - rect.top - delta >= spacing ) 
00344         rect.bottom -= delta;
00345 
00346     nstagger = (rect.bottom - rect.top)/(3 * spacing);
00347     lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
00348     lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
00349     lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
00350 }
00351 
00352 /**********************************************************************
00353  *            MDISetMenu
00354  */
00355 static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
00356                            HMENU hmenuWindow)
00357 {
00358     MDICLIENTINFO *ci;
00359     HWND hwndFrame = GetParent(hwnd);
00360     HMENU oldFrameMenu = GetMenu(hwndFrame);
00361 
00362     TRACE("%04x %04x %04x\n",
00363                 hwnd, hmenuFrame, hmenuWindow);
00364 
00365     if (hmenuFrame && !IsMenu(hmenuFrame))
00366     {
00367         WARN("hmenuFrame is not a menu handle\n");
00368         return 0L;
00369     }
00370         
00371     if (hmenuWindow && !IsMenu(hmenuWindow))
00372     {
00373         WARN("hmenuWindow is not a menu handle\n");
00374         return 0L;
00375     }
00376 
00377     if (!(ci = get_client_info( hwnd ))) return 0;
00378 
00379     if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
00380         MDI_RestoreFrameMenu( GetParent(hwnd), ci->hwndChildMaximized );
00381 
00382     if( hmenuWindow && ci->hWindowMenu && hmenuWindow!=ci->hWindowMenu )
00383     {
00384         /* delete menu items from ci->hWindowMenu 
00385          * and add them to hmenuWindow */
00386 
00387         INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
00388         INT pos = GetMenuItemCount(hmenuWindow) + 1;
00389 
00390         AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
00391 
00392         if( ci->nActiveChildren )
00393         {
00394             INT j;
00395             LPWSTR buffer = NULL;
00396             MENUITEMINFOW mii;
00397             INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */
00398 
00399             if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
00400                 nbWindowsMenuItems = ci->nActiveChildren;
00401             else
00402                 nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;
00403 
00404             j = i - nbWindowsMenuItems + 1;
00405 
00406             for( ; i >= j ; i-- )
00407             {
00408                 memset(&mii, 0, sizeof(mii));
00409                 mii.cbSize = sizeof(mii);
00410                 mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
00411                   | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;
00412 
00413                 GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
00414                 if(mii.cch) { /* Menu is MFT_STRING */
00415                     mii.cch++; /* add room for '\0' */
00416                     buffer = HeapAlloc(GetProcessHeap(), 0,
00417                                        mii.cch * sizeof(WCHAR));
00418                     mii.dwTypeData = buffer;
00419                     GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
00420                 }
00421                 DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
00422                 InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
00423                 if(buffer) {
00424                     HeapFree(GetProcessHeap(), 0, buffer);
00425                     buffer = NULL;
00426                 }
00427             }
00428         }
00429 
00430         /* remove separator */
00431         DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION); 
00432 
00433         ci->hWindowMenu = hmenuWindow;
00434     } 
00435 
00436     if (hmenuFrame)
00437     {
00438         SetMenu(hwndFrame, hmenuFrame);
00439         if( hmenuFrame!=oldFrameMenu )
00440         {
00441             if( ci->hwndChildMaximized )
00442                 MDI_AugmentFrameMenu( GetParent(hwnd), ci->hwndChildMaximized );
00443             return oldFrameMenu;
00444         }
00445     }
00446     else
00447     {
00448         HMENU menu = GetMenu( GetParent(hwnd) );
00449         INT nItems = GetMenuItemCount(menu) - 1;
00450         UINT iId = GetMenuItemID(menu,nItems) ;
00451 
00452         if( !(iId == SC_RESTORE || iId == SC_CLOSE) )
00453         {
00454             /* SetMenu() may already have been called, meaning that this window
00455              * already has its menu. But they may have done a SetMenu() on
00456              * an MDI window, and called MDISetMenu() after the fact, meaning
00457              * that the "if" to this "else" wouldn't catch the need to
00458              * augment the frame menu.
00459              */
00460             if( ci->hwndChildMaximized )
00461                 MDI_AugmentFrameMenu( GetParent(hwnd), ci->hwndChildMaximized );
00462         }
00463     }
00464     return 0;
00465 }
00466 
00467 /**********************************************************************
00468  *            MDIRefreshMenu
00469  */
00470 static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
00471                            HMENU hmenuWindow)
00472 {
00473     HWND hwndFrame = GetParent(hwnd);
00474     HMENU oldFrameMenu = GetMenu(hwndFrame);
00475 
00476     TRACE("%04x %04x %04x\n",
00477                 hwnd, hmenuFrame, hmenuWindow);
00478 
00479     FIXME("partially function stub\n");
00480 
00481     return oldFrameMenu;
00482 }
00483 
00484 
00485 /* ------------------ MDI child window functions ---------------------- */
00486 
00487 
00488 /**********************************************************************
00489  *                                      MDICreateChild
00490  */
00491 static HWND MDICreateChild( HWND parent, MDICLIENTINFO *ci,
00492                             LPMDICREATESTRUCTA cs, BOOL unicode )
00493 {
00494     POINT          pos[2]; 
00495     DWORD            style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
00496     HWND             hwnd, hwndMax = 0;
00497     UINT wIDmenu = ci->idFirstChild + ci->nActiveChildren;
00498 #ifndef __WIN32OS2__
00499     WND *wndParent;
00500 #endif
00501     static const WCHAR lpstrDef[] = {'j','u','n','k','!',0};
00502 
00503     TRACE("origin %i,%i - dim %i,%i, style %08lx\n", 
00504                 cs->x, cs->y, cs->cx, cs->cy, cs->style);
00505     /* calculate placement */
00506     MDI_CalcDefaultChildPos(parent, ci->nTotalCreated++, pos, 0);
00507 
00508     if (cs->cx == CW_USEDEFAULT || !cs->cx) cs->cx = pos[1].x;
00509     if (cs->cy == CW_USEDEFAULT || !cs->cy) cs->cy = pos[1].y;
00510 
00511     if( cs->x == CW_USEDEFAULT )
00512     {
00513         cs->x = pos[0].x;
00514         cs->y = pos[0].y;
00515     }
00516 
00517     /* restore current maximized child */
00518     if( (style & WS_VISIBLE) && ci->hwndChildMaximized )
00519     {
00520         TRACE("Restoring current maximized child %04x\n", ci->hwndChildMaximized);
00521         if( style & WS_MAXIMIZE )
00522             SendMessageW(parent, WM_SETREDRAW, FALSE, 0L);
00523         hwndMax = ci->hwndChildMaximized;
00524         ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
00525         if( style & WS_MAXIMIZE )
00526             SendMessageW(parent, WM_SETREDRAW, TRUE, 0L);
00527     }
00528 
00529     if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
00530     /* this menu is needed to set a check mark in MDI_ChildActivate */
00531     if (ci->hWindowMenu != 0)
00532         AppendMenuW(ci->hWindowMenu, MF_STRING, wIDmenu, lpstrDef);
00533 
00534     ci->nActiveChildren++;
00535 
00536     /* fix window style */
00537 #ifdef __WIN32OS2__
00538     if( !(GetWindowLongA(parent, GWL_STYLE) & MDIS_ALLCHILDSTYLES) )
00539 #else
00540     wndParent = WIN_FindWndPtr( parent );
00541     if( !(wndParent->dwStyle & MDIS_ALLCHILDSTYLES) )
00542 #endif
00543     {
00544         TRACE("MDIS_ALLCHILDSTYLES is missing, fixing window style\n");
00545         style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
00546                   WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
00547         style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
00548     }
00549 
00550 #ifndef __WIN32OS2__
00551     if( wndParent->flags & WIN_ISWIN32 )
00552     {
00553         WIN_ReleaseWndPtr( wndParent );
00554 #endif
00555         if(unicode)
00556         {
00557             MDICREATESTRUCTW *csW = (MDICREATESTRUCTW *)cs;
00558             hwnd = CreateWindowW( csW->szClass, csW->szTitle, style, 
00559                                 csW->x, csW->y, csW->cx, csW->cy, parent,
00560                                 (HMENU)wIDmenu, csW->hOwner, csW );
00561         }
00562         else
00563             hwnd = CreateWindowA( cs->szClass, cs->szTitle, style, 
00564                                 cs->x, cs->y, cs->cx, cs->cy, parent,
00565                                 (HMENU)wIDmenu, cs->hOwner, cs );
00566 #ifndef __WIN32OS2__
00567     }
00568     else
00569     {
00570         MDICREATESTRUCT16 *cs16;
00571         LPSTR title, cls;
00572 
00573         WIN_ReleaseWndPtr( wndParent );
00574         cs16 = SEGPTR_NEW(MDICREATESTRUCT16);
00575         STRUCT32_MDICREATESTRUCT32Ato16( cs, cs16 );
00576         title = SEGPTR_STRDUP( cs->szTitle );
00577         cls   = SEGPTR_STRDUP( cs->szClass );
00578         cs16->szTitle = SEGPTR_GET(title);
00579         cs16->szClass = SEGPTR_GET(cls);
00580 
00581         hwnd = CreateWindow16( cs->szClass, cs->szTitle, style, 
00582                                cs16->x, cs16->y, cs16->cx, cs16->cy, parent,
00583                                (HMENU)wIDmenu, cs16->hOwner,
00584                                (LPVOID)SEGPTR_GET(cs16) );
00585         SEGPTR_FREE( title );
00586         SEGPTR_FREE( cls );
00587         SEGPTR_FREE( cs16 );
00588     }
00589 #endif
00590     /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */
00591 
00592     if (hwnd)
00593     {
00594         /* All MDI child windows have the WS_EX_MDICHILD style */
00595         SetWindowLongW( hwnd, GWL_EXSTYLE, GetWindowLongW( hwnd, GWL_EXSTYLE ) | WS_EX_MDICHILD );
00596 
00597         /*  If we have more than 9 windows, we must insert the new one at the
00598          *  9th position in order to see it in the "Windows" menu
00599          */
00600         if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
00601             MDI_SwapMenuItems( parent, GetWindowLongW( hwnd, GWL_ID ),
00602                                ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
00603 
00604         MDI_MenuModifyItem(parent, hwnd);
00605 
00606         /* Have we hit the "More Windows..." limit? If so, we must 
00607          * add a "More Windows..." option 
00608          */
00609         if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
00610         {
00611             WCHAR szTmp[50];
00612             LoadStringW(GetModuleHandleA("USER32"), MDI_IDS_MOREWINDOWS, szTmp, sizeof(szTmp)/sizeof(szTmp[0]));
00613 
00614             ModifyMenuW(ci->hWindowMenu,
00615                         ci->idFirstChild + MDI_MOREWINDOWSLIMIT, 
00616                         MF_BYCOMMAND | MF_STRING, 
00617                         ci->idFirstChild + MDI_MOREWINDOWSLIMIT, 
00618                         szTmp);
00619         }
00620 
00621         if( IsIconic(hwnd) && ci->hwndActiveChild )
00622         {
00623             TRACE("Minimizing created MDI child %04x\n", hwnd);
00624             ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
00625         }
00626         else
00627         {
00628             /* WS_VISIBLE is clear if a) the MDI client has
00629              * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
00630              * MDICreateStruct. If so the created window is not shown nor 
00631              * activated.
00632              */
00633             if (IsWindowVisible(hwnd)) ShowWindow(hwnd, SW_SHOW);
00634         }
00635         TRACE("created child - %04x\n",hwnd);
00636     }
00637     else
00638     {
00639         ci->nActiveChildren--;
00640         DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
00641         if( IsWindow(hwndMax) )
00642             ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
00643     }
00644         
00645     return hwnd;
00646 }
00647 
00648 /**********************************************************************
00649  *                      MDI_ChildGetMinMaxInfo
00650  *
00651  * Note: The rule here is that client rect of the maximized MDI child 
00652  *       is equal to the client rect of the MDI client window.
00653  */
00654 static void MDI_ChildGetMinMaxInfo( HWND client, HWND hwnd, MINMAXINFO* lpMinMax )
00655 {
00656     RECT rect;
00657 
00658     GetClientRect( client, &rect );
00659     AdjustWindowRectEx( &rect, GetWindowLongW( hwnd, GWL_STYLE ),
00660                         0, GetWindowLongW( hwnd, GWL_EXSTYLE ));
00661 
00662     lpMinMax->ptMaxSize.x = rect.right -= rect.left;
00663     lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
00664 
00665     lpMinMax->ptMaxPosition.x = rect.left;
00666     lpMinMax->ptMaxPosition.y = rect.top; 
00667 
00668     TRACE("max rect (%i,%i - %i, %i)\n", 
00669                         rect.left,rect.top,rect.right,rect.bottom);
00670 }
00671 
00672 /**********************************************************************
00673  *                      MDI_SwitchActiveChild
00674  * 
00675  * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
00676  *       being activated 
00677  */
00678 static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
00679                                    BOOL bNextWindow )
00680 {
00681     HWND           hwndTo    = 0;
00682     HWND           hwndPrev  = 0;
00683     MDICLIENTINFO *ci = get_client_info( clientHwnd );
00684 
00685     hwndTo = MDI_GetWindow(ci, childHwnd, bNextWindow, 0);
00686 
00687     TRACE("from %04x, to %04x\n",childHwnd,hwndTo);
00688 
00689     if ( !hwndTo ) return; /* no window to switch to */
00690 
00691     hwndPrev = ci->hwndActiveChild;
00692 
00693     if ( hwndTo != hwndPrev )
00694     {
00695         SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0, 
00696                       SWP_NOMOVE | SWP_NOSIZE );
00697 
00698         if( bNextWindow && hwndPrev )
00699             SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0, 
00700                           SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
00701     }
00702 }
00703 
00704 
00705 /**********************************************************************
00706  *                                      MDIDestroyChild
00707  */
00708 static LRESULT MDIDestroyChild( HWND parent, MDICLIENTINFO *ci,
00709                                 HWND child, BOOL flagDestroy )
00710 {
00711     if( child == ci->hwndActiveChild )
00712     {
00713         MDI_SwitchActiveChild(parent, child, TRUE);
00714 
00715         if( child == ci->hwndActiveChild )
00716         {
00717             ShowWindow( child, SW_HIDE);
00718             if( child == ci->hwndChildMaximized )
00719             {
00720                 HWND frame = GetParent(parent);
00721                 MDI_RestoreFrameMenu( frame, child );
00722                 ci->hwndChildMaximized = 0;
00723                 MDI_UpdateFrameText( frame, parent, TRUE, NULL);
00724             }
00725 
00726             MDI_ChildActivate(parent, 0);
00727         }
00728     }
00729 
00730     MDI_MenuDeleteItem(parent, child);
00731 
00732     ci->nActiveChildren--;
00733 
00734     TRACE("child destroyed - %04x\n",child);
00735 
00736     if (flagDestroy)
00737     {
00738         MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
00739         DestroyWindow(child);
00740     }
00741     return 0;
00742 }
00743 
00744 
00745 /**********************************************************************
00746  *                                      MDI_ChildActivate
00747  *
00748  * Note: hWndChild is NULL when last child is being destroyed
00749  */
00750 static LONG MDI_ChildActivate( HWND client, HWND child )
00751 {
00752     MDICLIENTINFO *clientInfo = get_client_info( client );
00753     HWND prevActiveWnd = clientInfo->hwndActiveChild;
00754     BOOL isActiveFrameWnd;
00755 
00756 #ifdef __WIN32OS2__
00757     if (!IsWindowEnabled( child )) {
00758         clientInfo->hwndActiveChild = 0;
00759         return 0;
00760     }
00761 #else
00762     if (!IsWindowEnabled( child )) return 0;
00763 #endif
00764 
00765     /* Don't activate if it is already active. Might happen 
00766        since ShowWindow DOES activate MDI children */
00767     if (clientInfo->hwndActiveChild == child) return 0;
00768 
00769     TRACE("%04x\n", child);
00770 
00771     isActiveFrameWnd = (GetActiveWindow() == GetParent(client));
00772 
00773     /* deactivate prev. active child */
00774     if(prevActiveWnd)
00775     {
00776         SetWindowLongA( prevActiveWnd, GWL_STYLE,
00777                         GetWindowLongA( prevActiveWnd, GWL_STYLE ) | WS_SYSMENU );
00778         SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
00779         SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd, (LPARAM)child);
00780         /* uncheck menu item */
00781         if( clientInfo->hWindowMenu )
00782         {
00783             UINT prevID = GetWindowLongA( prevActiveWnd, GWL_ID );
00784 
00785             if (prevID - clientInfo->idFirstChild < MDI_MOREWINDOWSLIMIT)
00786                 CheckMenuItem( clientInfo->hWindowMenu, prevID, 0);
00787             else
00788                 CheckMenuItem( clientInfo->hWindowMenu,
00789                                clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1, 0);
00790         }
00791     }
00792 
00793     /* set appearance */
00794     if (clientInfo->hwndChildMaximized && clientInfo->hwndChildMaximized != child)
00795     {
00796         if( child )
00797         {
00798             clientInfo->hwndActiveChild = child;
00799             ShowWindow( child, SW_SHOWMAXIMIZED);
00800         }
00801         else ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
00802     }
00803 
00804     clientInfo->hwndActiveChild = child;
00805 
00806     /* check if we have any children left */
00807     if( !child )
00808     {
00809         if( isActiveFrameWnd )
00810             SetFocus( client );
00811         return 0;
00812     }
00813 
00814     /* check menu item */
00815     if( clientInfo->hWindowMenu )
00816     {
00817         UINT id = GetWindowLongA( child, GWL_ID );
00818         /* The window to be activated must be displayed in the "Windows" menu */
00819         if (id >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
00820         {
00821             MDI_SwapMenuItems( GetParent(child),
00822                                id, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
00823             id = clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1;
00824             MDI_MenuModifyItem( GetParent(child), child );
00825         }
00826 
00827         CheckMenuItem(clientInfo->hWindowMenu, id, MF_CHECKED);
00828     }
00829     /* bring active child to the top */
00830     SetWindowPos( child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
00831 
00832     if( isActiveFrameWnd )
00833     {
00834             SendMessageA( child, WM_NCACTIVATE, TRUE, 0L);
00835             if( GetFocus() == client )
00836                 SendMessageA( client, WM_SETFOCUS, (WPARAM)client, 0L );
00837             else
00838                 SetFocus( client );
00839     }
00840     SendMessageA( child, WM_MDIACTIVATE, (WPARAM)prevActiveWnd, (LPARAM)child );
00841     return TRUE;
00842 }
00843 
00844 /* -------------------- MDI client window functions ------------------- */
00845 
00846 /**********************************************************************
00847  *                              CreateMDIMenuBitmap
00848  */
00849 static HBITMAP CreateMDIMenuBitmap(void)
00850 {
00851  HDC            hDCSrc  = CreateCompatibleDC(0);
00852  HDC            hDCDest = CreateCompatibleDC(hDCSrc);
00853  HBITMAP        hbClose = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE) );
00854  HBITMAP        hbCopy;
00855  HBITMAP        hobjSrc, hobjDest;
00856 
00857  hobjSrc = SelectObject(hDCSrc, hbClose);
00858  hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
00859  hobjDest = SelectObject(hDCDest, hbCopy);
00860 
00861  BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
00862           hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
00863   
00864  SelectObject(hDCSrc, hobjSrc);
00865  DeleteObject(hbClose);
00866  DeleteDC(hDCSrc);
00867 
00868  hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
00869 
00870  MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
00871  LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
00872 
00873  SelectObject(hDCDest, hobjSrc );
00874  SelectObject(hDCDest, hobjDest);
00875  DeleteDC(hDCDest);
00876 
00877  return hbCopy;
00878 }
00879 
00880 /**********************************************************************
00881  *                              MDICascade
00882  */
00883 static LONG MDICascade( HWND client, MDICLIENTINFO *ci )
00884 {
00885     HWND *win_array;
00886     BOOL has_icons = FALSE;
00887     int i, total;
00888 
00889     if (ci->hwndChildMaximized)
00890         SendMessageA( client, WM_MDIRESTORE,
00891                         (WPARAM)ci->hwndChildMaximized, 0);
00892 
00893     if (ci->nActiveChildren == 0) return 0;
00894 
00895     if (!(win_array = WIN_ListChildren( client ))) return 0;
00896 
00897     /* remove all the windows we don't want */
00898     for (i = total = 0; win_array[i]; i++)
00899     {
00900         if (!IsWindowVisible( win_array[i] )) continue;
00901         if (GetWindow( win_array[i], GW_OWNER )) continue; /* skip owned windows */
00902         if (IsIconic( win_array[i] ))
00903         {
00904             has_icons = TRUE;
00905             continue;
00906         }
00907         win_array[total++] = win_array[i];
00908     }
00909     win_array[total] = 0;
00910 
00911     if (total)
00912     {
00913         INT delta = 0, n = 0, i;
00914         POINT pos[2];
00915         if (has_icons) delta = GetSystemMetrics(SM_CYICONSPACING) + GetSystemMetrics(SM_CYICON);
00916 
00917         /* walk the list (backwards) and move windows */
00918         for (i = total - 1; i >= 0; i--)
00919         {
00920             TRACE("move %04x to (%ld,%ld) size [%ld,%ld]\n", 
00921                   win_array[i], pos[0].x, pos[0].y, pos[1].x, pos[1].y);
00922 
00923             MDI_CalcDefaultChildPos(client, n++, pos, delta);
00924             SetWindowPos( win_array[i], 0, pos[0].x, pos[0].y, pos[1].x, pos[1].y,
00925                           SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
00926         }
00927     }
00928     HeapFree( GetProcessHeap(), 0, win_array );
00929 
00930     if (has_icons) ArrangeIconicWindows( client );
00931     return 0;
00932 }
00933 
00934 /**********************************************************************
00935  *                                      MDITile
00936  */
00937 static void MDITile( HWND client, MDICLIENTINFO *ci, WPARAM wParam )
00938 {
00939     HWND *win_array;
00940     int i, total;
00941     BOOL has_icons = FALSE;
00942 
00943     if (ci->hwndChildMaximized)
00944         SendMessageA( client, WM_MDIRESTORE, (WPARAM)ci->hwndChildMaximized, 0);
00945 
00946     if (ci->nActiveChildren == 0) return;
00947 
00948     if (!(win_array = WIN_ListChildren( client ))) return;
00949 
00950     /* remove all the windows we don't want */
00951     for (i = total = 0; win_array[i]; i++)
00952     {
00953         if (!IsWindowVisible( win_array[i] )) continue;
00954         if (GetWindow( win_array[i], GW_OWNER )) continue; /* skip owned windows (icon titles) */
00955         if (IsIconic( win_array[i] ))
00956         {
00957             has_icons = TRUE;
00958             continue;
00959         }
00960         if ((wParam & MDITILE_SKIPDISABLED) && !IsWindowEnabled( win_array[i] )) continue;
00961         win_array[total++] = win_array[i];
00962     }
00963     win_array[total] = 0;
00964 
00965     TRACE("%u windows to tile\n", total);
00966 
00967     if (total)
00968     {
00969         HWND *pWnd = win_array;
00970         RECT rect;
00971         int x, y, xsize, ysize;
00972         int rows, columns, r, c, i;
00973 
00974         GetClientRect(client,&rect);
00975         rows    = (int) sqrt((double)total);
00976         columns = total / rows;
00977 
00978         if( wParam & MDITILE_HORIZONTAL )  /* version >= 3.1 */
00979         {
00980             i = rows;
00981             rows = columns;  /* exchange r and c */
00982             columns = i;
00983         }
00984 
00985         if (has_icons)
00986         {
00987             y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
00988             rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
00989         }
00990 
00991         ysize   = rect.bottom / rows;
00992         xsize   = rect.right  / columns;
00993 
00994         for (x = i = 0, c = 1; c <= columns && *pWnd; c++)
00995         {
00996             if (c == columns)
00997             {
00998                 rows  = total - i;
00999                 ysize = rect.bottom / rows;
01000             }
01001 
01002             y = 0;
01003             for (r = 1; r <= rows && *pWnd; r++, i++)
01004             {
01005                 SetWindowPos(*pWnd, 0, x, y, xsize, ysize,
01006                              SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
01007                 y += ysize;
01008                 pWnd++;
01009             }
01010             x += xsize;
01011         }
01012     }
01013     HeapFree( GetProcessHeap(), 0, win_array );
01014     if (has_icons) ArrangeIconicWindows( client );
01015 }
01016 
01017 /* ----------------------- Frame window ---------------------------- */
01018 
01019 
01020 /**********************************************************************
01021  *                                      MDI_AugmentFrameMenu
01022  */
01023 static BOOL MDI_AugmentFrameMenu( HWND frame, HWND hChild )
01024 {
01025     HMENU menu = GetMenu( frame );
01026 #ifndef __WIN32OS2__
01027     WND*        child = WIN_FindWndPtr(hChild);
01028 #endif
01029     HMENU       hSysPopup = 0;
01030   HBITMAP hSysMenuBitmap = 0;
01031 
01032     TRACE("frame %04x,child %04x\n",frame,hChild);
01033 
01034 #ifdef __WIN32OS2__
01035     if( !menu || !getSysMenu(hChild) )
01036     {
01037         return 0;
01038     }
01039 #else
01040     if( !menu || !child->hSysMenu )
01041     {
01042         WIN_ReleaseWndPtr(child);
01043         return 0;
01044     }
01045     WIN_ReleaseWndPtr(child);
01046 #endif
01047 
01048     /* create a copy of sysmenu popup and insert it into frame menu bar */
01049 
01050     if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
01051         return 0;
01052 
01053     AppendMenuA(menu,MF_HELP | MF_BITMAP,
01054                    SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
01055     AppendMenuA(menu,MF_HELP | MF_BITMAP,
01056                    SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
01057 
01058   /* In Win 95 look, the system menu is replaced by the child icon */
01059 
01060 #ifndef __WIN32OS2__
01061   if(TWEAK_WineLook > WIN31_LOOK)
01062 #endif
01063   {
01064     HICON hIcon = GetClassLongA(hChild, GCL_HICONSM);
01065     if (!hIcon)
01066       hIcon = GetClassLongA(hChild, GCL_HICON);
01067     if (hIcon)
01068     {
01069       HDC hMemDC;
01070       HBITMAP hBitmap, hOldBitmap;
01071       HBRUSH hBrush;
01072       HDC hdc = GetDC(hChild);
01073 
01074       if (hdc)
01075       {
01076         int cx, cy;
01077         cx = GetSystemMetrics(SM_CXSMICON);
01078         cy = GetSystemMetrics(SM_CYSMICON);
01079         hMemDC = CreateCompatibleDC(hdc);
01080         hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
01081         hOldBitmap = SelectObject(hMemDC, hBitmap);
01082         SetMapMode(hMemDC, MM_TEXT);
01083         hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
01084         DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
01085         SelectObject (hMemDC, hOldBitmap);
01086         DeleteObject(hBrush);
01087         DeleteDC(hMemDC);
01088         ReleaseDC(hChild, hdc);
01089         hSysMenuBitmap = hBitmap;
01090       }
01091     }
01092   }
01093 #ifndef __WIN32OS2__
01094   else
01095     hSysMenuBitmap = hBmpClose;
01096 #endif
01097 
01098     if( !InsertMenuA(menu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
01099                     hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
01100     {  
01101         TRACE("not inserted\n");
01102         DestroyMenu(hSysPopup); 
01103         return 0; 
01104     }
01105 
01106     /* The close button is only present in Win 95 look */
01107 #ifndef __WIN32OS2__
01108     if(TWEAK_WineLook > WIN31_LOOK)
01109     {
01110 #endif
01111         AppendMenuA(menu,MF_HELP | MF_BITMAP,
01112                        SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
01113 #ifndef __WIN32OS2__
01114     }
01115 #endif
01116 
01117     EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
01118     EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
01119     EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
01120     SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
01121 
01122     /* redraw menu */
01123     DrawMenuBar(frame);
01124 
01125     return 1;
01126 }
01127 
01128 /**********************************************************************
01129  *                                      MDI_RestoreFrameMenu
01130  */
01131 static BOOL MDI_RestoreFrameMenu( HWND frame, HWND hChild )
01132 {
01133     MENUITEMINFOW menuInfo;
01134     HMENU menu = GetMenu( frame );
01135     INT nItems = GetMenuItemCount(menu) - 1;
01136     UINT iId = GetMenuItemID(menu,nItems) ;
01137 
01138     TRACE("frame %04x,child %04x,nIt=%d,iId=%d\n",frame,hChild,nItems,iId);
01139 
01140     if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
01141         return 0; 
01142 
01143     /*
01144      * Remove the system menu, If that menu is the icon of the window
01145      * as it is in win95, we have to delete the bitmap.
01146      */
01147     memset(&menuInfo, 0, sizeof(menuInfo));
01148     menuInfo.cbSize = sizeof(menuInfo);
01149     menuInfo.fMask  = MIIM_DATA | MIIM_TYPE;
01150 
01151     GetMenuItemInfoW(menu,
01152                      0, 
01153                      TRUE,
01154                      &menuInfo);
01155 
01156     RemoveMenu(menu,0,MF_BYPOSITION);
01157 
01158     if ( (menuInfo.fType & MFT_BITMAP)           &&
01159          (LOWORD(menuInfo.dwTypeData)!=0)        &&
01160          (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
01161     {
01162       DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
01163     }
01164 
01165 #ifndef __WIN32OS2__
01166     if(TWEAK_WineLook > WIN31_LOOK)
01167     {
01168 #endif
01169         /* close */
01170         DeleteMenu(menu,GetMenuItemCount(menu) - 1,MF_BYPOSITION);
01171 #ifndef __WIN32OS2__
01172     }
01173 #endif
01174     /* restore */
01175     DeleteMenu(menu,GetMenuItemCount(menu) - 1,MF_BYPOSITION);
01176     /* minimize */
01177     DeleteMenu(menu,GetMenuItemCount(menu) - 1,MF_BYPOSITION);
01178 
01179     DrawMenuBar(frame);
01180 
01181     return 1;
01182 }
01183 
01184 
01185 /**********************************************************************
01186  *                                      MDI_UpdateFrameText
01187  *
01188  * used when child window is maximized/restored 
01189  *
01190  * Note: lpTitle can be NULL
01191  */
01192 static void MDI_UpdateFrameText( HWND frame, HWND hClient,
01193                                  BOOL repaint, LPCWSTR lpTitle )
01194 {
01195     WCHAR   lpBuffer[MDI_MAXTITLELENGTH+1];
01196     MDICLIENTINFO *ci = get_client_info( hClient );
01197 
01198     TRACE("repaint %i, frameText %s\n", repaint, debugstr_w(lpTitle));
01199 
01200     if (!ci) return;
01201 
01202     if (!lpTitle && !ci->frameTitle)  /* first time around, get title from the frame window */
01203     {
01204         GetWindowTextW( frame, lpBuffer, sizeof(lpBuffer)/sizeof(WCHAR) );
01205         lpTitle = lpBuffer;
01206     }
01207 
01208     /* store new "default" title if lpTitle is not NULL */
01209     if (lpTitle) 
01210     {
01211         if (ci->frameTitle) HeapFree( GetProcessHeap(), 0, ci->frameTitle );
01212         if ((ci->frameTitle = HeapAlloc( GetProcessHeap(), 0, (strlenW(lpTitle)+1)*sizeof(WCHAR))))
01213             strcpyW( ci->frameTitle, lpTitle );
01214     }
01215 
01216     if (ci->frameTitle)
01217     {
01218         if (ci->hwndChildMaximized)
01219         {
01220             /* combine frame title and child title if possible */
01221 
01222             static const WCHAR lpBracket[]  = {' ','-',' ','[',0};
01223             static const WCHAR lpBracket2[]  = {']',0};
01224             int i_frame_text_length = strlenW(ci->frameTitle);
01225 
01226             lstrcpynW( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
01227 
01228             if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
01229             {
01230                 strcatW( lpBuffer, lpBracket );
01231                 if (GetWindowTextW( ci->hwndChildMaximized, lpBuffer + i_frame_text_length + 4,
01232                                     MDI_MAXTITLELENGTH - i_frame_text_length - 5 ))
01233                     strcatW( lpBuffer, lpBracket2 );
01234                 else
01235                     lpBuffer[i_frame_text_length] = 0;  /* remove bracket */
01236             }
01237         }
01238         else
01239         {
01240             lstrcpynW(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
01241         }
01242     }
01243     else
01244         lpBuffer[0] = '\0';
01245 
01246     DefWindowProcW( frame, WM_SETTEXT, 0, (LPARAM)lpBuffer );
01247     if( repaint == MDI_REPAINTFRAME)
01248         SetWindowPos( frame, 0,0,0,0,0, SWP_FRAMECHANGED |
01249                       SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
01250 }
01251 
01252 
01253 /* ----------------------------- Interface ---------------------------- */
01254 
01255 
01256 /**********************************************************************
01257  *              MDIClientWndProc_common
01258  */
01259 static LRESULT MDIClientWndProc_common( HWND hwnd, UINT message,
01260                                         WPARAM wParam, LPARAM lParam, BOOL unicode )
01261 {
01262     MDICLIENTINFO *ci;
01263 
01264     if (!(ci = get_client_info( hwnd ))) return 0;
01265 
01266     switch (message)
01267     {
01268       case WM_CREATE:
01269       {
01270           RECT rect;
01271           /* Since we are using only cs->lpCreateParams, we can safely
01272            * cast to LPCREATESTRUCTA here */
01273           LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam;
01274 #ifndef __WIN32OS2__
01275           WND *wndPtr = WIN_FindWndPtr( hwnd );
01276 
01277         /* Translation layer doesn't know what's in the cs->lpCreateParams
01278          * so we have to keep track of what environment we're in. */
01279 
01280         if( wndPtr->flags & WIN_ISWIN32 )
01281         {
01282 #endif
01283 #define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
01284             ci->hWindowMenu     = ccs->hWindowMenu;
01285             ci->idFirstChild    = ccs->idFirstChild;
01286 #undef ccs
01287 #ifndef __WIN32OS2__
01288         }
01289         else    
01290         {
01291             LPCLIENTCREATESTRUCT16 ccs = MapSL((SEGPTR)cs->lpCreateParams);
01292             ci->hWindowMenu     = ccs->hWindowMenu;
01293             ci->idFirstChild    = ccs->idFirstChild;
01294         }
01295         WIN_ReleaseWndPtr( wndPtr );
01296 #endif
01297 
01298         ci->hwndChildMaximized  = 0;
01299         ci->nActiveChildren     = 0;
01300         ci->nTotalCreated       = 0;
01301         ci->frameTitle          = NULL;
01302         ci->mdiFlags            = 0;
01303         SetWindowLongW( hwnd, GWL_STYLE, GetWindowLongW(hwnd,GWL_STYLE) | WS_CLIPCHILDREN );
01304 
01305         if (!hBmpClose)
01306         {
01307             hBmpClose = CreateMDIMenuBitmap();
01308             hBmpRestore = LoadBitmapW( 0, MAKEINTRESOURCEW(OBM_RESTORE) );
01309         }
01310 
01311         if (ci->hWindowMenu != 0)
01312             AppendMenuW( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
01313 
01314         GetClientRect( GetParent(hwnd), &rect);
01315         MoveWindow( hwnd, 0, 0, rect.right, rect.bottom, FALSE );
01316 
01317         MDI_UpdateFrameText( GetParent(hwnd), hwnd, MDI_NOFRAMEREPAINT, NULL);
01318 
01319         TRACE("Client created - hwnd = %04x, idFirst = %u\n",
01320               hwnd, ci->idFirstChild );
01321         return 0;
01322       }
01323 
01324       case WM_DESTROY:
01325       {
01326           INT nItems;
01327           if( ci->hwndChildMaximized )
01328               MDI_RestoreFrameMenu( GetParent(hwnd), ci->hwndChildMaximized);
01329           if((ci->hWindowMenu != 0) &&
01330              (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
01331           {
01332               ci->idFirstChild = nItems - 1;
01333               ci->nActiveChildren++;  /* to delete a separator */
01334               while( ci->nActiveChildren-- )
01335                   DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
01336           }
01337           if (ci->frameTitle) HeapFree( GetProcessHeap(), 0, ci->frameTitle );
01338           return 0;
01339       }
01340 
01341       case WM_MDIACTIVATE:
01342         if( ci->hwndActiveChild != (HWND)wParam )
01343             SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
01344         return 0;
01345 
01346       case WM_MDICASCADE:
01347         return MDICascade(hwnd, ci);
01348 
01349       case WM_MDICREATE:
01350         if (lParam) return MDICreateChild( hwnd, ci,
01351                                            (MDICREATESTRUCTA *)lParam, unicode );
01352         else return 0;
01353 
01354       case WM_MDIDESTROY:
01355           return MDIDestroyChild( hwnd, ci, WIN_GetFullHandle( (HWND)wParam ), TRUE );
01356 
01357       case WM_MDIGETACTIVE:
01358           if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized != 0);
01359           return ci->hwndActiveChild;
01360 
01361       case WM_MDIICONARRANGE:
01362         ci->mdiFlags |= MDIF_NEEDUPDATE;
01363         ArrangeIconicWindows( hwnd );
01364         ci->sbRecalc = SB_BOTH+1;
01365         SendMessageW( hwnd, WM_MDICALCCHILDSCROLL, 0, 0 );
01366         return 0;
01367 
01368       case WM_MDIMAXIMIZE:
01369         ShowWindow( (HWND)wParam, SW_MAXIMIZE );
01370         return 0;
01371 
01372       case WM_MDINEXT: /* lParam != 0 means previous window */
01373         MDI_SwitchActiveChild( hwnd, WIN_GetFullHandle( (HWND)wParam ), !lParam );
01374         break;
01375         
01376       case WM_MDIRESTORE:
01377         SendMessageW( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
01378         return 0;
01379 
01380       case WM_MDISETMENU:
01381           return MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
01382 
01383       case WM_MDIREFRESHMENU:
01384           return MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
01385 
01386       case WM_MDITILE:
01387         ci->mdiFlags |= MDIF_NEEDUPDATE;
01388         ShowScrollBar( hwnd, SB_BOTH, FALSE );
01389         MDITile( hwnd, ci, wParam );
01390         ci->mdiFlags &= ~MDIF_NEEDUPDATE;
01391         return 0;
01392 
01393       case WM_VSCROLL:
01394       case WM_HSCROLL:
01395         ci->mdiFlags |= MDIF_NEEDUPDATE;
01396         ScrollChildren( hwnd, message, wParam, lParam );
01397         ci->mdiFlags &= ~MDIF_NEEDUPDATE;
01398         return 0;
01399 
01400       case WM_SETFOCUS:
01401           if (ci->hwndActiveChild && !IsIconic( ci->hwndActiveChild ))
01402               SetFocus( ci->hwndActiveChild );
01403           return 0;
01404 
01405       case WM_NCACTIVATE:
01406         if( ci->hwndActiveChild )
01407             SendMessageW(ci->hwndActiveChild, message, wParam, lParam);
01408         break;
01409 
01410       case WM_PARENTNOTIFY:
01411         if (LOWORD(wParam) == WM_LBUTTONDOWN)
01412         {
01413             HWND child;
01414             POINT pt;
01415             pt.x = SLOWORD(lParam);
01416             pt.y = SHIWORD(lParam);
01417             child = ChildWindowFromPoint(hwnd, pt);
01418 
01419             TRACE("notification from %04x (%li,%li)\n",child,pt.x,pt.y);
01420 
01421             if( child && child != hwnd && child != ci->hwndActiveChild )
01422                 SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
01423         }
01424         return 0;
01425 
01426       case WM_SIZE:
01427         if( IsWindow(ci->hwndChildMaximized) )
01428         {
01429             RECT        rect;
01430 
01431             rect.left = 0;
01432             rect.top = 0;
01433             rect.right = LOWORD(lParam);
01434             rect.bottom = HIWORD(lParam);
01435 
01436             AdjustWindowRectEx(&rect, GetWindowLongA(ci->hwndChildMaximized,GWL_STYLE),
01437                                0, GetWindowLongA(ci->hwndChildMaximized,GWL_EXSTYLE) );
01438             MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
01439                          rect.right - rect.left, rect.bottom - rect.top, 1);
01440         }
01441         else
01442             MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
01443 
01444         break;
01445 
01446       case WM_MDICALCCHILDSCROLL:
01447         if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
01448         {
01449             CalcChildScroll(hwnd, ci->sbRecalc-1);
01450             ci->sbRecalc = 0;
01451             ci->mdiFlags &= ~MDIF_NEEDUPDATE;
01452         }
01453         return 0;
01454     }
01455     return unicode ? DefWindowProcW( hwnd, message, wParam, lParam ) :
01456                      DefWindowProcA( hwnd, message, wParam, lParam );
01457 }
01458 
01459 /***********************************************************************
01460  *              MDIClientWndProcA
01461  */
01462 #ifdef __WIN32OS2__
01463        LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
01464 #else
01465 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
01466 #endif
01467 {
01468     if (!IsWindow(hwnd)) return 0;
01469     return MDIClientWndProc_common( hwnd, message, wParam, lParam, FALSE );
01470 }
01471 
01472 /***********************************************************************
01473  *              MDIClientWndProcW
01474  */
01475 static LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
01476 {
01477     if (!IsWindow(hwnd)) return 0;
01478     return MDIClientWndProc_common( hwnd, message, wParam, lParam, TRUE );
01479 }
01480 
01481 #ifndef __WIN32OS2__
01482 /***********************************************************************
01483  *              DefFrameProc (USER.445)
01484  */
01485 LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
01486                                UINT16 message, WPARAM16 wParam, LPARAM lParam )
01487 {
01488     switch (message)
01489     {
01490     case WM_SETTEXT:
01491         return DefFrameProcA( hwnd, hwndMDIClient, message, wParam, (LPARAM)MapSL(lParam) );
01492 
01493     case WM_COMMAND:
01494     case WM_NCACTIVATE:
01495     case WM_SETFOCUS:
01496     case WM_SIZE:
01497         return DefFrameProcW( hwnd, hwndMDIClient, message, wParam, lParam );
01498 
01499     case WM_NEXTMENU:
01500         {
01501             MDINEXTMENU next_menu;
01502             DefFrameProcW( hwnd, hwndMDIClient, message, wParam, (LPARAM)&next_menu );
01503             return MAKELONG( next_menu.hmenuNext, next_menu.hwndNext );
01504         }
01505     default:
01506         return DefWindowProc16(hwnd, message, wParam, lParam);
01507     }
01508 }
01509 #endif
01510 
01511 /***********************************************************************
01512  *              DefFrameProcA (USER32.@)
01513  */
01514 LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
01515                                 UINT message, WPARAM wParam, LPARAM lParam)
01516 {
01517     if (hwndMDIClient)
01518     {
01519         switch (message)
01520         {
01521         case WM_SETTEXT:
01522             {
01523                 LPWSTR text = HEAP_strdupAtoW( GetProcessHeap(), 0, (LPSTR)lParam );
01524                 MDI_UpdateFrameText(hwnd, hwndMDIClient, MDI_REPAINTFRAME, text );
01525                 HeapFree( GetProcessHeap(), 0, text );
01526             }
01527             return 1; /* success. FIXME: check text length */
01528 
01529         case WM_COMMAND:
01530         case WM_NCACTIVATE:
01531         case WM_NEXTMENU:
01532         case WM_SETFOCUS:
01533         case WM_SIZE:
01534             return DefFrameProcW( hwnd, hwndMDIClient, message, wParam, lParam );
01535         }
01536     }
01537     return DefWindowProcA(hwnd, message, wParam, lParam);
01538 }
01539 
01540 
01541 /***********************************************************************
01542  *              DefFrameProcW (USER32.@)
01543  */
01544 LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
01545                                 UINT message, WPARAM wParam, LPARAM lParam)
01546 {
01547     MDICLIENTINFO *ci = get_client_info( hwndMDIClient );
01548 
01549     if (ci)
01550     {
01551         switch (message)
01552         {
01553         case WM_COMMAND:
01554             {
01555                 WORD id = LOWORD(wParam);
01556                 /* check for possible syscommands for maximized MDI child */
01557                 if (id <  ci->idFirstChild || id >= ci->idFirstChild + ci->nActiveChildren)
01558                 {
01559                     if( (id - 0xf000) & 0xf00f ) break;
01560                     if( !ci->hwndChildMaximized ) break;
01561                     switch( id )
01562                     {
01563                     case SC_SIZE:
01564                     case SC_MOVE:
01565                     case SC_MINIMIZE:
01566                     case SC_MAXIMIZE:
01567                     case SC_NEXTWINDOW:
01568                     case SC_PREVWINDOW:
01569                     case SC_CLOSE:
01570                     case SC_RESTORE:
01571                         return SendMessageW( ci->hwndChildMaximized, WM_SYSCOMMAND,
01572                                              wParam, lParam);
01573                     }
01574                 }
01575                 else
01576                 {
01577                     HWND childHwnd;
01578                     if (id - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
01579                         /* User chose "More Windows..." */
01580                         childHwnd = MDI_MoreWindowsDialog(hwndMDIClient);
01581                     else
01582                         /* User chose one of the windows listed in the "Windows" menu */
01583                         childHwnd = MDI_GetChildByID(hwndMDIClient,id);
01584 
01585                     if( childHwnd )
01586                         SendMessageW( hwndMDIClient, WM_MDIACTIVATE, (WPARAM)childHwnd, 0 );
01587                 }
01588             }
01589             break;
01590 
01591         case WM_NCACTIVATE:
01592             SendMessageW(hwndMDIClient, message, wParam, lParam);
01593             break;
01594 
01595         case WM_SETTEXT: 
01596             MDI_UpdateFrameText(hwnd, hwndMDIClient, MDI_REPAINTFRAME, (LPWSTR)lParam );
01597             return 1; /* success. FIXME: check text length */
01598 
01599         case WM_SETFOCUS:
01600             SetFocus(hwndMDIClient);
01601             break;
01602 
01603         case WM_SIZE:
01604             MoveWindow(hwndMDIClient, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
01605             break;
01606 
01607         case WM_NEXTMENU:
01608             {
01609                 MDINEXTMENU *next_menu = (MDINEXTMENU *)lParam;
01610 
01611                 if (!IsIconic(hwnd) && ci->hwndActiveChild && !ci->hwndChildMaximized)
01612                 {
01613                     /* control menu is between the frame system menu and 
01614                      * the first entry of menu bar */
01615 #ifdef __WIN32OS2__
01616                     if( (wParam == VK_LEFT && GetMenu(hwnd) == next_menu->hmenuIn) ||
01617                         (wParam == VK_RIGHT && GetSubMenu(getSysMenu(hwnd), 0) == next_menu->hmenuIn) )
01618                     {
01619                         next_menu->hmenuNext = GetSubMenu(getSysMenu(ci->hwndActiveChild), 0);
01620                         next_menu->hwndNext = ci->hwndActiveChild;
01621                     }
01622 #else
01623 
01624                     WND *wndPtr = WIN_FindWndPtr(hwnd);
01625 
01626                     if( (wParam == VK_LEFT && GetMenu(hwnd) == next_menu->hmenuIn) ||
01627                         (wParam == VK_RIGHT && GetSubMenu(wndPtr->hSysMenu, 0) == next_menu->hmenuIn) )
01628                     {
01629                         WIN_ReleaseWndPtr(wndPtr);
01630                         wndPtr = WIN_FindWndPtr(ci->hwndActiveChild);
01631                         next_menu->hmenuNext = GetSubMenu(wndPtr->hSysMenu, 0);
01632                         next_menu->hwndNext = ci->hwndActiveChild;
01633                         WIN_ReleaseWndPtr(wndPtr);
01634                     }
01635 #endif
01636                 }
01637                 return 0;
01638             }
01639         }
01640     }
01641 
01642     return DefWindowProcW( hwnd, message, wParam, lParam );
01643 }
01644 
01645 
01646 #ifndef __WIN32OS2__
01647 /***********************************************************************
01648  *              DefMDIChildProc (USER.447)
01649  */
01650 LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
01651                                   WPARAM16 wParam, LPARAM lParam )
01652 {
01653     switch (message)
01654     {
01655     case WM_SETTEXT:
01656         return DefMDIChildProcA( WIN_Handle32(hwnd), message, wParam, (LPARAM)MapSL(lParam) );
01657     case WM_MENUCHAR:
01658     case WM_CLOSE:
01659     case WM_SETFOCUS:
01660     case WM_CHILDACTIVATE:
01661     case WM_SYSCOMMAND:
01662     case WM_SETVISIBLE:
01663     case WM_SIZE:
01664     case WM_SYSCHAR:
01665         return DefMDIChildProcW( WIN_Handle32(hwnd), message, wParam, lParam );
01666     case WM_GETMINMAXINFO:
01667         {
01668             MINMAXINFO16 *mmi16 = (MINMAXINFO16 *)MapSL(lParam);
01669             MINMAXINFO mmi;
01670             STRUCT32_MINMAXINFO16to32( mmi16, &mmi );
01671             DefMDIChildProcW( WIN_Handle32(hwnd), message, wParam, (LPARAM)&mmi );
01672             STRUCT32_MINMAXINFO32to16( &mmi, mmi16 );
01673             return 0;
01674         }
01675     case WM_NEXTMENU:
01676         {
01677             MDINEXTMENU next_menu;
01678             DefMDIChildProcW( WIN_Handle32(hwnd), message, wParam, (LPARAM)&next_menu );
01679             return MAKELONG( next_menu.hmenuNext, next_menu.hwndNext );
01680         }
01681     default:
01682         return DefWindowProc16(hwnd, message, wParam, lParam);
01683     }
01684 }
01685 #endif
01686 
01687 /***********************************************************************
01688  *              DefMDIChildProcA (USER32.@)
01689  */
01690 LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
01691                                    WPARAM wParam, LPARAM lParam )
01692 {
01693     HWND client = GetParent(hwnd);
01694     MDICLIENTINFO *ci = get_client_info( client );
01695 
01696     hwnd = WIN_GetFullHandle( hwnd );
01697     if (!ci) return DefWindowProcA( hwnd, message, wParam, lParam );
01698 
01699     switch (message)
01700     {
01701     case WM_SETTEXT:
01702         DefWindowProcA(hwnd, message, wParam, lParam);
01703         MDI_MenuModifyItem( client, hwnd );
01704         if( ci->hwndChildMaximized == hwnd )
01705             MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL );
01706         return 1; /* success. FIXME: check text length */
01707 
01708     case WM_GETMINMAXINFO:
01709     case WM_MENUCHAR:
01710     case WM_CLOSE:
01711     case WM_SETFOCUS:
01712     case WM_CHILDACTIVATE:
01713     case WM_SYSCOMMAND:
01714     case WM_SETVISIBLE:
01715     case WM_SIZE:
01716     case WM_NEXTMENU:
01717     case WM_SYSCHAR:
01718         return DefMDIChildProcW( hwnd, message, wParam, lParam );
01719     }
01720     return DefWindowProcA(hwnd, message, wParam, lParam);
01721 }
01722 
01723 
01724 /***********************************************************************
01725  *              DefMDIChildProcW (USER32.@)
01726  */
01727 LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
01728                                    WPARAM wParam, LPARAM lParam )
01729 {
01730     HWND client = GetParent(hwnd);
01731     MDICLIENTINFO *ci = get_client_info( client );
01732 
01733     hwnd = WIN_GetFullHandle( hwnd );
01734     if (!ci) return DefWindowProcW( hwnd, message, wParam, lParam );
01735 
01736     switch (message)
01737     {
01738     case WM_SETTEXT:
01739         DefWindowProcW(hwnd, message, wParam, lParam);
01740         MDI_MenuModifyItem( client, hwnd );
01741         if( ci->hwndChildMaximized == hwnd )
01742             MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL );
01743         return 1; /* success. FIXME: check text length */
01744 
01745     case WM_GETMINMAXINFO:
01746         MDI_ChildGetMinMaxInfo( client, hwnd, (MINMAXINFO *)lParam );
01747         return 0;
01748 
01749     case WM_MENUCHAR:
01750         return 0x00010000; /* MDI children don't have menu bars */
01751 
01752     case WM_CLOSE:
01753         SendMessageW( client, WM_MDIDESTROY, (WPARAM)hwnd, 0 );
01754         return 0;
01755 
01756     case WM_SETFOCUS:
01757         if (ci->hwndActiveChild != hwnd) MDI_ChildActivate( client, hwnd );
01758         break;
01759 
01760     case WM_CHILDACTIVATE:
01761         MDI_ChildActivate( client, hwnd );
01762         return 0;
01763 
01764     case WM_SYSCOMMAND:
01765         switch( wParam )
01766         {
01767         case SC_MOVE:
01768             if( ci->hwndChildMaximized == hwnd) return 0;
01769             break;
01770         case SC_RESTORE:
01771         case SC_MINIMIZE:
01772             SetWindowLongA( hwnd, GWL_STYLE,
01773                             GetWindowLongA( hwnd, GWL_STYLE ) | WS_SYSMENU );
01774             break;
01775         case SC_MAXIMIZE:
01776             if (ci->hwndChildMaximized == hwnd)
01777                 return SendMessageW( GetParent(client), message, wParam, lParam);
01778             SetWindowLongW( hwnd, GWL_STYLE,
01779                             GetWindowLongW( hwnd, GWL_STYLE ) & ~WS_SYSMENU );
01780             break;
01781         case SC_NEXTWINDOW:
01782             SendMessageW( client, WM_MDINEXT, 0, 0);
01783             return 0;
01784         case SC_PREVWINDOW:
01785             SendMessageW( client, WM_MDINEXT, 0, 1);
01786             return 0;
01787         }
01788         break;
01789 
01790     case WM_SETVISIBLE:
01791         if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
01792         else MDI_PostUpdate(client, ci, SB_BOTH+1);
01793         break;
01794 
01795     case WM_SIZE:
01796         if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
01797         {
01798             ci->hwndChildMaximized = 0;
01799             MDI_RestoreFrameMenu( GetParent(client), hwnd );
01800             MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL );
01801         }
01802 
01803         if( wParam == SIZE_MAXIMIZED )
01804         {
01805             HWND hMaxChild = ci->hwndChildMaximized;
01806 
01807             if( hMaxChild == hwnd ) break;
01808             if( hMaxChild)
01809             {
01810                 SendMessageW( hMaxChild, WM_SETREDRAW, FALSE, 0 );
01811                 MDI_RestoreFrameMenu( GetParent(client), hMaxChild );
01812                 ShowWindow( hMaxChild, SW_SHOWNOACTIVATE );
01813                 SendMessageW( hMaxChild, WM_SETREDRAW, TRUE, 0 );
01814             }
01815             TRACE("maximizing child %04x\n", hwnd );
01816 
01817             /* keep track of the maximized window. */
01818             ci->hwndChildMaximized = hwnd; /* !!! */
01819 
01820             /* The maximized window should also be the active window */
01821             MDI_ChildActivate( client, hwnd );
01822             MDI_AugmentFrameMenu( GetParent(client), hwnd );
01823             MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL );
01824         }
01825 
01826         if( wParam == SIZE_MINIMIZED )
01827         {
01828             HWND switchTo = MDI_GetWindow(ci, hwnd, TRUE, WS_MINIMIZE);
01829 
01830             if (switchTo) SendMessageW( switchTo, WM_CHILDACTIVATE, 0, 0);
01831         }
01832         MDI_PostUpdate(client, ci, SB_BOTH+1);
01833         break;
01834 
01835     case WM_NEXTMENU:
01836         {
01837             MDINEXTMENU *next_menu = (MDINEXTMENU *)lParam;
01838             HWND parent = GetParent(client);
01839 
01840             if( wParam == VK_LEFT )  /* switch to frame system menu */
01841             {
01842 #ifdef __WIN32OS2__
01843                 next_menu->hmenuNext = GetSubMenu( getSysMenu(parent), 0 );
01844 #else
01845                 WND *wndPtr = WIN_FindWndPtr( parent );
01846                 next_menu->hmenuNext = GetSubMenu( wndPtr->hSysMenu, 0 );
01847                 WIN_ReleaseWndPtr( wndPtr );
01848 #endif
01849             }
01850             if( wParam == VK_RIGHT )  /* to frame menu bar */
01851             {
01852                 next_menu->hmenuNext = GetMenu(parent);
01853             }
01854             next_menu->hwndNext = parent;
01855             return 0;
01856         }
01857 
01858     case WM_SYSCHAR:
01859         if (wParam == '-')
01860         {
01861             SendMessageW( hwnd, WM_SYSCOMMAND, (WPARAM)SC_KEYMENU, (DWORD)VK_SPACE);
01862             return 0;
01863         }
01864         break;
01865     }
01866     return DefWindowProcW(hwnd, message, wParam, lParam);
01867 }
01868 
01869 /**********************************************************************
01870  *              CreateMDIWindowA (USER32.@) Creates a MDI child
01871  *
01872  * RETURNS
01873  *    Success: Handle to created window
01874  *    Failure: NULL
01875  */
01876 HWND WINAPI CreateMDIWindowA(
01877     LPCSTR lpClassName,    /* [in] Pointer to registered child class name */
01878     LPCSTR lpWindowName,   /* [in] Pointer to window name */
01879     DWORD dwStyle,         /* [in] Window style */
01880     INT X,               /* [in] Horizontal position of window */
01881     INT Y,               /* [in] Vertical position of window */
01882     INT nWidth,          /* [in] Width of window */
01883     INT nHeight,         /* [in] Height of window */
01884     HWND hWndParent,     /* [in] Handle to parent window */
01885     HINSTANCE hInstance, /* [in] Handle to application instance */
01886     LPARAM lParam)         /* [in] Application-defined value */
01887 {
01888     MDICLIENTINFO *pCi = get_client_info( hWndParent );
01889     MDICREATESTRUCTA cs;
01890 
01891     TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
01892           debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
01893           nWidth,nHeight,hWndParent,hInstance,lParam);
01894 
01895     if (!pCi)
01896     {
01897         ERR("bad hwnd for MDI-client: %04x\n", hWndParent);
01898         return 0;
01899     }
01900     cs.szClass=lpClassName;
01901     cs.szTitle=lpWindowName;
01902     cs.hOwner=hInstance;
01903     cs.x=X;
01904     cs.y=Y;
01905     cs.cx=nWidth;
01906     cs.cy=nHeight;
01907     cs.style=dwStyle;
01908     cs.lParam=lParam;
01909 
01910     return MDICreateChild(hWndParent, pCi, &cs, FALSE);
01911 }
01912 
01913 /***********************************************************************
01914  *              CreateMDIWindowW (USER32.@) Creates a MDI child
01915  *
01916  * RETURNS
01917  *    Success: Handle to created window
01918  *    Failure: NULL
01919  */
01920 HWND WINAPI CreateMDIWindowW(
01921     LPCWSTR lpClassName,    /* [in] Pointer to registered child class name */
01922     LPCWSTR lpWindowName,   /* [in] Pointer to window name */
01923     DWORD dwStyle,         /* [in] Window style */
01924     INT X,               /* [in] Horizontal position of window */
01925     INT Y,               /* [in] Vertical position of window */
01926     INT nWidth,          /* [in] Width of window */
01927     INT nHeight,         /* [in] Height of window */
01928     HWND hWndParent,     /* [in] Handle to parent window */
01929     HINSTANCE hInstance, /* [in] Handle to application instance */
01930     LPARAM lParam)         /* [in] Application-defined value */
01931 {
01932     MDICLIENTINFO *pCi = get_client_info( hWndParent );
01933     MDICREATESTRUCTW cs;
01934 
01935     TRACE("(%s,%s,%ld,%d,%d,%d,%d,%x,%d,%ld)\n",
01936           debugstr_w(lpClassName), debugstr_w(lpWindowName), dwStyle, X, Y,
01937           nWidth, nHeight, hWndParent, hInstance, lParam);
01938 
01939     if (!pCi)
01940     {
01941         ERR("bad hwnd for MDI-client: %04x\n", hWndParent);
01942         return 0;
01943     }
01944     cs.szClass = lpClassName;
01945     cs.szTitle = lpWindowName;
01946     cs.hOwner = hInstance;
01947     cs.x = X;
01948     cs.y = Y;
01949     cs.cx = nWidth;
01950     cs.cy = nHeight;
01951     cs.style = dwStyle;
01952     cs.lParam = lParam;
01953 
01954     return MDICreateChild(hWndParent, pCi, (MDICREATESTRUCTA *)&cs, TRUE);
01955 }
01956 
01957 #ifndef __WIN32OS2__
01958 /**********************************************************************
01959  *              TranslateMDISysAccel (USER.451)
01960  */
01961 BOOL16 WINAPI TranslateMDISysAccel16( HWND16 hwndClient, LPMSG16 msg )
01962 {
01963     if (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN)
01964     {
01965         MSG msg32;
01966         msg32.hwnd    = msg->hwnd;
01967         msg32.message = msg->message;
01968         msg32.wParam  = msg->wParam;
01969         msg32.lParam  = msg->lParam;
01970         /* MDICLIENTINFO is still the same for win32 and win16 ... */
01971         return TranslateMDISysAccel(hwndClient, &msg32);
01972     }
01973     return 0;
01974 }
01975 #endif
01976 
01977 /**********************************************************************
01978  *              TranslateMDISysAccel (USER32.@)
01979  */
01980 BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
01981 {
01982     if (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN)
01983     {
01984         MDICLIENTINFO *ci = get_client_info( hwndClient );
01985         WPARAM wParam = 0;
01986 
01987         if (!ci || !IsWindowEnabled(ci->hwndActiveChild)) return 0;
01988 
01989         /* translate if the Ctrl key is down and Alt not. */
01990 
01991         if( (GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_MENU) & 0x8000))
01992         {
01993             switch( msg->wParam )
01994             {
01995             case VK_F6:
01996             case VK_TAB:
01997                 wParam = ( GetKeyState(VK_SHIFT) & 0x8000 ) ? SC_NEXTWINDOW : SC_PREVWINDOW;
01998                 break;
01999             case VK_F4:
02000             case VK_RBUTTON:
02001                 wParam = SC_CLOSE;
02002                 break;
02003             default:
02004                 return 0;
02005             }
02006             TRACE("wParam = %04x\n", wParam);
02007             SendMessageW(ci->hwndActiveChild, WM_SYSCOMMAND, wParam, (LPARAM)msg->wParam);
02008             return 1;
02009         }
02010     }
02011     return 0; /* failure */
02012 }
02013 
02014 #ifndef __WIN32OS2__
02015 /***********************************************************************
02016  *              CalcChildScroll (USER.462)
02017  */
02018 void WINAPI CalcChildScroll16( HWND16 hwnd, WORD scroll )
02019 {
02020     return CalcChildScroll( hwnd, scroll );
02021 }
02022 #endif
02023 
02024 /***********************************************************************
02025  *              CalcChildScroll (USER32.@)
02026  */
02027 void WINAPI CalcChildScroll( HWND hwnd, INT scroll )
02028 {
02029     SCROLLINFO info;
02030     RECT childRect, clientRect;
02031     INT  vmin, vmax, hmin, hmax, vpos, hpos;
02032     HWND *list;
02033 
02034     GetClientRect( hwnd, &clientRect );
02035     SetRectEmpty( &childRect );
02036 
02037     if ((list = WIN_ListChildren( hwnd )))
02038     {
02039         int i;
02040         for (i = 0; list[i]; i++)
02041         {
02042             DWORD style = GetWindowLongW( list[i], GWL_STYLE );
02043             if (style & WS_MAXIMIZE)
02044             {
02045                 HeapFree( GetProcessHeap(), 0, list );
02046                 ShowScrollBar( hwnd, SB_BOTH, FALSE );
02047                 return;
02048             }
02049             if (style & WS_VISIBLE)
02050             {
02051 #ifdef __WIN32OS2__
02052                 RECT rect;
02053                 GetWindowRectParent(list[i], &rect);
02054                 UnionRect( &childRect, &rect, &childRect );
02055 #else
02056                 WND *pWnd = WIN_FindWndPtr( list[i] );
02057                 UnionRect( &childRect, &pWnd->rectWindow, &childRect );
02058                 WIN_ReleaseWndPtr( pWnd );
02059 #endif
02060             }
02061         }
02062         HeapFree( GetProcessHeap(), 0, list );
02063     }
02064     UnionRect( &childRect, &clientRect, &childRect );
02065 
02066     hmin = childRect.left;
02067     hmax = childRect.right - clientRect.right;
02068     hpos = clientRect.left - childRect.left;
02069     vmin = childRect.top;
02070     vmax = childRect.bottom - clientRect.bottom;
02071     vpos = clientRect.top - childRect.top;
02072 
02073     switch( scroll )
02074     {
02075         case SB_HORZ:
02076                         vpos = hpos; vmin = hmin; vmax = hmax;
02077         case SB_VERT:
02078                         info.cbSize = sizeof(info);
02079                         info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
02080                         info.fMask = SIF_POS | SIF_RANGE;
02081                         SetScrollInfo(hwnd, scroll, &info, TRUE);
02082                         break;
02083         case SB_BOTH:
02084                         SCROLL_SetNCSbState( hwnd, vmin, vmax, vpos,
02085                                              hmin, hmax, hpos);
02086     }    
02087 }
02088 
02089 
02090 #ifndef __WIN32OS2__
02091 /***********************************************************************
02092  *              ScrollChildren (USER.463)
02093  */
02094 void WINAPI ScrollChildren16(HWND16 hWnd, UINT16 uMsg, WPARAM16 wParam, LPARAM lParam)
02095 {
02096     ScrollChildren( hWnd, uMsg, wParam, lParam );
02097 }
02098 #endif
02099 
02100 /***********************************************************************
02101  *              ScrollChildren (USER32.@)
02102  */
02103 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
02104                              LPARAM lParam)
02105 {
02106     INT newPos = -1;
02107     INT curPos, length, minPos, maxPos, shift;
02108     RECT rect;
02109 
02110     GetClientRect( hWnd, &rect );
02111 
02112     switch(uMsg)
02113     {
02114     case WM_HSCROLL:
02115         GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
02116         curPos = GetScrollPos(hWnd,SB_HORZ);
02117         length = (rect.right - rect.left) / 2;
02118         shift = GetSystemMetrics(SM_CYHSCROLL);
02119         break;
02120     case WM_VSCROLL:
02121         GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
02122         curPos = GetScrollPos(hWnd,SB_VERT);
02123         length = (rect.bottom - rect.top) / 2;
02124         shift = GetSystemMetrics(SM_CXVSCROLL);
02125         break;
02126     default:
02127         return;
02128     }
02129 
02130     switch( wParam )
02131     {
02132         case SB_LINEUP: 
02133                         newPos = curPos - shift;
02134                         break;
02135         case SB_LINEDOWN:    
02136                         newPos = curPos + shift;
02137                         break;
02138         case SB_PAGEUP: 
02139                         newPos = curPos - length;
02140                         break;
02141         case SB_PAGEDOWN:    
02142                         newPos = curPos + length;
02143                         break;
02144 
02145         case SB_THUMBPOSITION: 
02146                         newPos = LOWORD(lParam);
02147                         break;
02148 
02149         case SB_THUMBTRACK:  
02150                         return;
02151 
02152         case SB_TOP:            
02153                         newPos = minPos;
02154                         break;
02155         case SB_BOTTOM: 
02156                         newPos = maxPos;
02157                         break;
02158         case SB_ENDSCROLL:
02159                         CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
02160                         return;
02161     }
02162 
02163     if( newPos > maxPos )
02164         newPos = maxPos;
02165     else 
02166         if( newPos < minPos )
02167             newPos = minPos;
02168 
02169     SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
02170 
02171     if( uMsg == WM_VSCROLL )
02172         ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL, 
02173                         SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
02174     else
02175         ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
02176                         SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
02177 }
02178 
02179 
02180 /******************************************************************************
02181  *              CascadeWindows (USER32.@) Cascades MDI child windows
02182  *
02183  * RETURNS
02184  *    Success: Number of cascaded windows.
02185  *    Failure: 0
02186  */
02187 WORD WINAPI
02188 CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
02189                 UINT cKids, const HWND *lpKids)
02190 {
02191     FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
02192            hwndParent, wFlags, cKids);
02193 
02194     return 0;
02195 }
02196 
02197 
02198 /******************************************************************************
02199  *              TileWindows (USER32.@) Tiles MDI child windows
02200  *
02201  * RETURNS
02202  *    Success: Number of tiled windows.
02203  *    Failure: 0
02204  */
02205 WORD WINAPI
02206 TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
02207              UINT cKids, const HWND *lpKids)
02208 {
02209     FIXME("(0x%08x,0x%08x,...,%u,...): stub\n",
02210            hwndParent, wFlags, cKids);
02211 
02212     return 0;
02213 }
02214 
02215 /************************************************************************
02216  *              "More Windows..." functionality
02217  */
02218 
02219 /*              MDI_MoreWindowsDlgProc
02220  *
02221  *    This function will process the messages sent to the "More Windows..."
02222  *    dialog.
02223  *    Return values:  0    = cancel pressed
02224  *                    HWND = ok pressed or double-click in the list...
02225  *
02226  */
02227 
02228 static BOOL WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
02229 {
02230     switch (iMsg)
02231     {
02232        case WM_INITDIALOG:
02233        {
02234            UINT widest       = 0;
02235            UINT length;
02236            UINT i;
02237            MDICLIENTINFO *ci = get_client_info( (HWND)lParam );
02238            HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
02239            HWND *list, *sorted_list;
02240 
02241            if (!(list = WIN_ListChildren( (HWND)lParam ))) return TRUE;
02242            if (!(sorted_list = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
02243                                           sizeof(HWND) * ci->nActiveChildren )))
02244            {
02245                HeapFree( GetProcessHeap(), 0, list );
02246                return FALSE;
02247            }
02248 
02249            /* Fill the list, sorted by id... */
02250            for (i = 0; list[i]; i++)
02251            {
02252                UINT id = GetWindowLongW( list[i], GWL_ID ) - ci->idFirstChild;
02253                if (id < ci->nActiveChildren) sorted_list[id] = list[i];
02254            }
02255            HeapFree( GetProcessHeap(), 0, list );
02256 
02257            for (i = 0; i < ci->nActiveChildren; i++)
02258            {
02259                WCHAR buffer[128];
02260 
02261                if (!GetWindowTextW( sorted_list[i], buffer, sizeof(buffer)/sizeof(WCHAR) ))
02262                    continue;
02263                SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM)buffer );
02264                SendMessageW(hListBox, LB_SETITEMDATA, i, (LPARAM)sorted_list[i] );
02265                length = strlenW(buffer);  /* FIXME: should use GetTextExtentPoint */
02266                if (length > widest)
02267                    widest = length;
02268            }
02269            /* Make sure the horizontal scrollbar scrolls ok */
02270            SendMessageW(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0);
02271 
02272            /* Set the current selection */
02273            SendMessageW(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
02274            return TRUE;
02275        }
02276 
02277        case WM_COMMAND:
02278            switch (LOWORD(wParam))
02279            {
02280                 default:
02281                     if (HIWORD(wParam) != LBN_DBLCLK) break;
02282                     /* fall through */
02283                 case IDOK:
02284                 {
02285                     /*  windows are sorted by menu ID, so we must return the
02286                      *  window associated to the given id
02287                      */
02288                     HWND hListBox     = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
02289                     UINT index        = SendMessageW(hListBox, LB_GETCURSEL, 0, 0);
02290                     HWND hwnd         = SendMessageW(hListBox, LB_GETITEMDATA, index, 0);
02291 
02292                     EndDialog(hDlg, hwnd);
02293                     return TRUE;
02294                 }
02295                 case IDCANCEL:
02296                     EndDialog(hDlg, 0);
02297                     return TRUE;
02298            }
02299            break;
02300     }
02301     return FALSE;
02302 }
02303 
02304 /*
02305  *
02306  *                      MDI_MoreWindowsDialog
02307  *
02308  *     Prompts the user with a listbox containing the opened
02309  *     documents. The user can then choose a windows and click
02310  *     on OK to set the current window to the one selected, or
02311  *     CANCEL to cancel. The function returns a handle to the
02312  *     selected window.
02313  */
02314 
02315 static HWND MDI_MoreWindowsDialog(HWND hwnd)
02316 {
02317     LPCVOID template;
02318     HRSRC hRes;
02319     HANDLE hDlgTmpl;
02320 
02321     hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", RT_DIALOGA);
02322 
02323     if (hRes == 0)
02324         return 0;
02325 
02326     hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );
02327 
02328     if (hDlgTmpl == 0)
02329         return 0;
02330 
02331     template = LockResource( hDlgTmpl );
02332 
02333     if (template == 0)
02334         return 0;
02335 
02336     return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
02337                                           (LPDLGTEMPLATEA) template,
02338                                           hwnd, MDI_MoreWindowsDlgProc, (LPARAM) hwnd);
02339 }
02340 
02341 /*
02342  *
02343  *                      MDI_SwapMenuItems
02344  *
02345  *      Will swap the menu IDs for the given 2 positions.
02346  *      pos1 and pos2 are menu IDs
02347  *     
02348  *    
02349  */
02350 
02351 static void MDI_SwapMenuItems(HWND parent, UINT pos1, UINT pos2)
02352 {
02353     HWND *list;
02354     int i;
02355 
02356     if (!(list = WIN_ListChildren( parent ))) return;
02357     for (i = 0; list[i]; i++)
02358     {
02359         UINT id = GetWindowLongW( list[i], GWL_ID );
02360         if (id == pos1) SetWindowLongW( list[i], GWL_ID, pos2 );
02361         else if (id == pos2) SetWindowLongW( list[i], GWL_ID, pos1 );
02362     }
02363     HeapFree( GetProcessHeap(), 0, list );
02364 }
02365 
02366 #ifdef __WIN32OS2__
02367 
02368 #define MDICLIENTCLASSNAMEA "MDICLIENT"
02369 #define MDICLIENTCLASSNAMEW L"MDICLIENT"
02370 
02371 //******************************************************************************
02372 //******************************************************************************
02373 BOOL MDICLIENT_Register()
02374 {
02375     WNDCLASSA wndClass;
02376 
02377 //SvL: Don't check this now
02378 //    if (GlobalFindAtomA(MDICLIENTCLASSNAMEA)) return FALSE;
02379 
02380     ZeroMemory(&wndClass,sizeof(WNDCLASSA));
02381     wndClass.style         = CS_GLOBALCLASS;
02382     wndClass.lpfnWndProc   = (WNDPROC)MDIClientWndProcA;
02383     wndClass.cbClsExtra    = 0;
02384     wndClass.cbWndExtra    = 0;
02385     wndClass.hCursor       = LoadCursorA(0,IDC_ARROWA);;
02386     wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
02387     wndClass.lpszClassName = MDICLIENTCLASSNAMEA;
02388 
02389     return RegisterClassA(&wndClass);
02390 }
02391 //******************************************************************************
02392 //******************************************************************************
02393 BOOL MDICLIENT_Unregister()
02394 {
02395     if (GlobalFindAtomA(MDICLIENTCLASSNAMEA))
02396             return UnregisterClassA(MDICLIENTCLASSNAMEA,(HINSTANCE)NULL);
02397     else    return FALSE;
02398 }
02399 //******************************************************************************
02400 //******************************************************************************
02401 #endif

Generated on Wed Jan 23 23:17:35 2002 for ODIN-user32 by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001