Release 951212

Mon Dec 11 19:08:55 1995  Alexandre Julliard  <julliard@sunsite.unc.edu>

	* [misc/lstr.c]
	Replaced wine_strncpy() by a 32-bit version of lstrcpyn(), since
 	they do the same job.

	* [tools/build.c]
	Fixed __attribute__((stdcall)) to make it compile with gcc
	versions under 2.7. Doesn't mean it will run OK though...

Sat Dec 09 13:22:58 1995  Cameron Heide  <heide@ee.ualberta.ca>

	* [include/kernel32.h] [include/winerror.h]
	Added file attribute definitions and more error codes.

	* [win32/error.c]
	Added some rudimentary errno-to-Win32 error conversion
	code.

	* [win32/file.c]
	Added to GetFileInformationByHandle, filled in some known
	error codes, and switched to dprintf_win32.

	* [win32/time.c]
	Added GetLocalTime.

Fri Dec  8 14:37:39 1995  Jim Peterson <jspeter@birch.ee.vt.edu>

	* [controls/combo.c]
	Converted functions of the type LONG _(HWND,WORD,LONG) to the type
	LRESULT _(HWND,WPARAM,LPARAM) where needed.

	* [include/libres.h]
	Restructured libres prototypes to closer match the windows API.

	* [include/windows.h]
	Changed several API prototypes' parameter types from 'short' to INT,
	which is #defined as short in the emulator, but is a normal int in
	WINELIB32.  Also changed SEGPTR from DWORD to void* when WINELIB32.
	(This creates a lot of warnings at library-compile time, but less
	warnings at app-compile time.  I'll remove the warnings soon.)

	* [loader/resource.c]
	Fixed parameter mismatch in call to LIBRES_FindResource().  Changed
	various implementations of the LIBRES_* API functions.

	* [loader/signal.c]
	Deleted local 'i' from win_fault(), since it was unused.

	* [objects/bitblt.c]
	Mirrored changes to include/windows.h mentioned above.

	* [toolkit/hello3.c]
	Changed LoadMenuIndirect() call to LoadMenu() to test the new
	resource registration technique.

	* [toolkit/libres.c]
	Removed definition of 'struct resource' and fixed bugs in the resource
	implementation.  Implemented LIBRES_FindResource.

	* [windows/graphics.c]
	Mirrored changes to include/windows.h mentioned above.

Thu Dec  7 23:15:56 1995     Martin von Loewis <loewis@informatik.hu-berlin.de>

	* [controls/edit.c]
	LOCAL_HeapExists: Changed parameter to HANDLE. For WineLib, return true

	* [controls/listbox.c]
	CreateListBoxStruct: Initialize HeapSel to 0 for WineLib

	* [include/listbox.h]
	change HeapSel from WORD to HANDLE

	* [include/resource.h][rc/winerc.c]
	struct ResourceTable: removed
	struct resource: moved to header file
	autoregister resources if supported by compiler

	* [memory/local.h]
	LOCAL_GetHeap: expect HANDLE rather than WORD
	
	* [toolkit/Makefile.in]
	Add ALLCFLAGS to make hello3

	* [toolkit/heap.c]
	LocalFree, HEAP_Free: handle 0 parameter gracefully

Wed Dec 06 15:34:23 1995  Greg Cooper <cooper@ima-inc.com>

	* [misc/winsocket.c]
	Fixed the msgsnd and msgrcv errors that winsock programs get.

Wed Dec 06 12:47:23 MET 1995 Sven Verdoolaege <skimo@dns.ufsia.ac.be>
	
	* [if1632/kernel.spec]
	Fixed _hread and _hwrite return type

	* [if1632/relay32.c] [loader/pe_image.c]
	Hacked loading of PE-dll's in

	* [win32/advapi.c]
	Added stubs for RegCreateKeyEx, RegSetValueEx, RegQueryValueEx

	* [win32/file.c]
	Added stubs for OpenFileMapping, CreateFileMapping, MapViewOfFileEx

	* [win32/process.c]
	Added stubs for CreateMutexA, ReleaseMutex, CreateEventA,
	WaitForSingleObject, DuplicateHandle, GetCurrentProcess
	
Mon Dec 04 13:06:37 1995   Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>

	* [include/wine.h] [misc/lstr.c]
	Define wine_strncpy(). This function does not pad the buffer with 
	zeroes like GNU strncpy(), which might break some Windows programs
	that pass bogus size arguments.

	* [loader/module.c]: GetModuleFileName(),
	[misc/commdlg.c]: GetFileTitle(),
	[misc/keyboard.c], [misc/lstr.c]: lstrcpyn(),
	[misc/ole2nls.c], [misc/profile.c], [multimedia/mcistring.c],
	[multimedia/mmsystem.c], [objects/font.c]:
	Use wine_strncpy() where strings are returned to Windows programs.
	
	* [objects/metafile.c]
	PlayMetafile(): Clear the handle table before using it.

	* [misc/shell.c] [misc/main.c]
	Rename SHELL_RegCheckForRoot() to SHELL_Init() and call it from main().
	
	* [misc/profile.c]
	load(): Need to handle comments.
	
	* [toolkit/libres.c]
	Make it compile.
	
	* [windows/nonclient.c]
	Use MAKE_SEGPTR macro in two places where a user heap block used
	to be allocated instead.

Sat Dec 02 16:43:43 1995 Ramon Garcia <ramon@ie3.clubs.etsit.upm.es>

	* [windows/winpos.c]
	In function SetWindowPos: do not redraw the parent of
	a window if the specified window is placed on the top.
	This avoids that ShowWindow(hwnd,1) hides hwnd instead
	of showing it.

Sat Dec 02 11:00:00 1995 Alex Korobka <alex@phm30.pharm.sunysb.edu>

	* [windows/scroll.c]
	Now it can scroll children along with the client region of parent 
        window. Tried to optimize update region calculation. 

	* [windows/mdi.c]
	ScrollChildren function, more other features added. Basically
	a rewrite.

	* [windows/winpos.c] [windows/focus.c]
	Reimplemented window activation and focus handling.

	* [windows/nonclient.c]
	Added new flag WIN_NCACTIVATED.

	* [windows/message.c] [loader/task.c]
	Small changes (to maintain linked list of message queues).

Wed Nov 29 15:51:48 1995  Daniel Schepler  <daniel@shep13.wustl.edu>

	* [include/options.h] [misc/main.c] [windows/defwnd.c]
	  [windows/event.c] [windows/nonclient.c] [windows/win.c] [Wine.man]
	Implemented a -managed option to replace the standard Windows
	frame of top-level windows with the window manager's decorations.
	If a top-level window makes its own frame, this will still show
	up, inside the window manager decorations (I believe ctl3dv2.dll
	would do this, although I can't test this).
diff --git a/windows/mdi.c b/windows/mdi.c
index e1a3ddf..0fe19aa 100644
--- a/windows/mdi.c
+++ b/windows/mdi.c
@@ -1,10 +1,20 @@
 /* MDI.C
  *
  * Copyright 1994, Bob Amstadt
+ *           1995, Alex Korobka
  *
  * This file contains routines to support MDI features.
+ *
+ * Notes: Windows keeps ID of MDI menu item in the wIDenu field
+ *        of corresponding MDI child.
+ *
+ *	  Basic child activation routine is MDI_ChildActivate and 
+ *        SetWindowPos(childHwnd,...) implicitly calls it if SWP_NOACTIVATE i
+ *        is not used.
  */
+
 #include <stdlib.h>
+#include <string.h>
 #include <stdio.h>
 #include <math.h>
 #include "windows.h"
@@ -17,50 +27,168 @@
 #include "stddebug.h"
 #include "debug.h"
 
-/**********************************************************************
- *					MDIRecreateMenuList
+void ScrollChildren(HWND , UINT , WPARAM , LPARAM );
+void CalcChildScroll(HWND, WORD);
+
+/* ----------------- declarations ----------------- */
+
+static LONG MDI_ChildActivate(WND* ,HWND );
+
+/* -------- Miscellaneous service functions ----------
+ *
+ *			MDI_GetChildByID
  */
-void MDIRecreateMenuList(MDICLIENTINFO *ci)
+
+static HWND MDI_GetChildByID(WND* mdiClient,int id)
 {
-    HLOCAL hinfo;
+ HWND	hWnd   = mdiClient->hwndChild;
+ WND* 	wndPtr = WIN_FindWndPtr( hWnd );
     
-    char buffer[128];
-    int id, n, index;
+ if( !wndPtr ) return 0;
 
-    dprintf_mdi(stddeb, "MDIRecreateMenuList: hWindowMenu "NPFMT"\n", 
-	    ci->hWindowMenu);
-    
-    id = ci->idFirstChild; 
-    while (DeleteMenu(ci->hWindowMenu, id, MF_BYCOMMAND))
-	id++;
+ while( wndPtr )
+  {
+	if( wndPtr->wIDmenu == id ) return hWnd;
+ 	wndPtr = WIN_FindWndPtr(hWnd = wndPtr->hwndNext);
+  }
 
-    dprintf_mdi(stddeb, "MDIRecreateMenuList: id %04x, idFirstChild %04x\n", 
-	    id, ci->idFirstChild);
-
-    if (!ci->flagMenuAltered)
-    {
-	ci->flagMenuAltered = TRUE;
-	AppendMenu(ci->hWindowMenu, MF_SEPARATOR, 0, NULL);
-    }
-    
-    id = ci->idFirstChild;
-    index = 1;
-    for (hinfo = ci->infoActiveChildren; hinfo != 0;)
-    {
-	MDICHILDINFO *chi = USER_HEAP_LIN_ADDR(hinfo);
-	
-	n = sprintf(buffer, "%d ", index++);
-	GetWindowText(chi->hwnd, buffer + n, sizeof(buffer) - n - 1);
-
-	dprintf_mdi(stddeb, "MDIRecreateMenuList: id %04x, '%s'\n",
-		id, buffer);
-
-	AppendMenu(ci->hWindowMenu, MF_STRING, id++, buffer);
-	hinfo = chi->next;
-    }
+ return 0;
 }
 
 /**********************************************************************
+ *			MDI_MenuAppendItem
+ */
+static BOOL MDI_MenuAppendItem(WND *clientWnd, HWND hWndChild)
+{
+    char buffer[128];
+ MDICLIENTINFO  *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
+ WND		*wndPtr     = WIN_FindWndPtr(hWndChild);
+ LPSTR		 lpWndText  = (LPSTR) USER_HEAP_LIN_ADDR(wndPtr->hText);
+ int 		 n          = sprintf(buffer, "%d ", 
+				      clientInfo->nActiveChildren);
+
+ if( !clientInfo->hWindowMenu ) return 0; 
+    
+ if( lpWndText )
+     strncpy(buffer + n, lpWndText, sizeof(buffer) - n - 1);
+ return AppendMenu(clientInfo->hWindowMenu,MF_STRING,
+                       wndPtr->wIDmenu,(LPSTR)buffer);
+}
+
+/**********************************************************************
+ *			MDI_MenuModifyItem
+ */
+static BOOL MDI_MenuModifyItem(WND* clientWnd, HWND hWndChild )
+{
+ char            buffer[128];
+ MDICLIENTINFO  *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
+ WND            *wndPtr     = WIN_FindWndPtr(hWndChild);
+ LPSTR           lpWndText  = (LPSTR) USER_HEAP_LIN_ADDR(wndPtr->hText);
+ UINT		 n          = sprintf(buffer, "%d ",
+                              wndPtr->wIDmenu - clientInfo->idFirstChild + 1);
+ BOOL		 bRet	    = 0;
+
+ if( !clientInfo->hWindowMenu ) return 0;
+
+ if( lpWndText )
+     strncpy(buffer + n, lpWndText, sizeof(buffer) - n - 1);
+
+ n    = GetMenuState(clientInfo->hWindowMenu,wndPtr->wIDmenu ,MF_BYCOMMAND); 
+ bRet = ModifyMenu(clientInfo->hWindowMenu , wndPtr->wIDmenu , 
+                   MF_BYCOMMAND | MF_STRING, wndPtr->wIDmenu ,(LPSTR)buffer );
+        CheckMenuItem(clientInfo->hWindowMenu ,wndPtr->wIDmenu , n & MF_CHECKED);
+ return bRet;
+}
+
+/**********************************************************************
+ *			MDI_MenuDeleteItem
+ */
+static BOOL MDI_MenuDeleteItem(WND* clientWnd, HWND hWndChild )
+{
+ char    	 buffer[128];
+ MDICLIENTINFO  *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
+ WND    	*wndPtr     = WIN_FindWndPtr(hWndChild);
+ LPSTR		 lpWndText;
+ INT		 index      = 0,id,n;
+
+ if( !clientInfo->nActiveChildren ||
+     !clientInfo->hWindowMenu ) return 0;
+
+ id = wndPtr->wIDmenu;
+ DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
+
+ /* walk the rest of MDI children to prevent gaps in the id 
+  * sequence and in the menu child list 
+  */
+
+ for( index = id+1; index <= clientInfo->nActiveChildren + 
+                             clientInfo->idFirstChild; index++ )
+    {
+	wndPtr = WIN_FindWndPtr(MDI_GetChildByID(clientWnd,index));
+	if( !wndPtr )
+	     {
+	      dprintf_mdi(stddeb,"MDIMenuDeleteItem: no window for id=%i\n",index);
+	      continue;
+    }
+    
+	/* set correct id */
+	wndPtr->wIDmenu--;
+
+	n          = sprintf(buffer, "%d ",index - clientInfo->idFirstChild);
+	lpWndText  = (LPSTR) USER_HEAP_LIN_ADDR(wndPtr->hText);
+
+	if( lpWndText )
+	    strncpy(buffer + n, lpWndText, sizeof(buffer) - n - 1);	
+
+	/* change menu */
+	ModifyMenu(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
+		   index - 1 ,(LPSTR)buffer ); 
+    }
+ return 1;
+}
+
+/**********************************************************************
+ * 			MDI_GetWindow
+ *
+ * returns "activateable" child  or zero
+ */
+HWND MDI_GetWindow(WND  *clientWnd, HWND hWnd, WORD wTo )
+{
+ HWND            hWndNext;
+ MDICLIENTINFO  *clientInfo = (MDICLIENTINFO*)clientWnd->wExtra;
+ WND            *wndPtr;
+
+ if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
+
+ if( !(wndPtr = WIN_FindWndPtr(hWnd)) ) return 0;
+
+ hWndNext = hWnd;
+ wTo      = wTo ? GW_HWNDPREV : GW_HWNDNEXT;
+
+ while( hWndNext )
+    {
+        if( clientWnd->hwndChild == hWndNext && wTo == GW_HWNDPREV )
+             hWndNext = GetWindow( hWndNext, GW_HWNDLAST);
+        else if( wndPtr->hwndNext == 0 && wTo == GW_HWNDNEXT )
+                 hWndNext = clientWnd->hwndChild;
+             else
+                 hWndNext = GetWindow( hWndNext, wTo );
+	
+        wndPtr = WIN_FindWndPtr( hWndNext );
+
+        if( (wndPtr->dwStyle & WS_VISIBLE) &&
+           !(wndPtr->dwStyle & WS_DISABLED) )
+             break;
+
+        /* check if all windows were iterated through */
+        if( hWndNext == hWnd ) break;
+    }
+
+ return ( hWnd == hWndNext )? 0 : hWndNext;
+}
+
+
+/**********************************************************************
  *					MDISetMenu
  * FIXME: This is not complete.
  */
@@ -94,7 +222,9 @@
 {
     MDICREATESTRUCT *cs = (MDICREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
     HWND hwnd;
+    WORD	     wIDmenu = ci->idFirstChild + ci->nActiveChildren;
     int spacing;
+    char	     chDef = '\0';
 
     /*
      * Create child window
@@ -107,133 +237,68 @@
     cs->x = ci->nActiveChildren * spacing;  
     cs->y = ci->nActiveChildren * spacing;
 
+    /* this menu is needed to set a check mark in MDI_ChildActivate */
+    AppendMenu(ci->hWindowMenu ,MF_STRING ,wIDmenu, (LPSTR)&chDef);
+
     hwnd = CreateWindow( cs->szClass, cs->szTitle,
 			  WS_CHILD | WS_BORDER | WS_CAPTION | WS_CLIPSIBLINGS |
 			  WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU |
 			  WS_THICKFRAME | WS_VISIBLE | cs->style,
-			  cs->x, cs->y, cs->cx, cs->cy, parent, (HMENU) 0,
-			  w->hInstance, (SEGPTR)lParam);
+			  cs->x, cs->y, cs->cx, cs->cy, parent, 
+                         (HMENU) wIDmenu, w->hInstance, (SEGPTR)lParam);
 
     if (hwnd)
     {
-	HANDLE h = USER_HEAP_ALLOC( sizeof(MDICHILDINFO) );
-	MDICHILDINFO *child_info = USER_HEAP_LIN_ADDR(h);
-	
-	if (!h)
-	{
-	    DestroyWindow(hwnd);
-	    return 0;
-	}
-
 	ci->nActiveChildren++;
+	MDI_MenuModifyItem(w ,hwnd); 
 
-	child_info->next = ci->infoActiveChildren;
-	child_info->prev = 0;
-	child_info->hwnd = hwnd;
-
-	if (ci->infoActiveChildren) {
-	    MDICHILDINFO *nextinfo = USER_HEAP_LIN_ADDR(ci->infoActiveChildren);
-	    nextinfo->prev = h;
-	}
-
-	ci->infoActiveChildren = h;
-
-	SendMessage(parent, WM_CHILDACTIVATE, 0, 0);
+	/* FIXME: at this point NC area of hwnd stays inactive */
     }
+    else
+	DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
 	
     return hwnd;
 }
 
 /**********************************************************************
- *					MDIDestroyChild
+ *			MDI_SwitchActiveChild
+ * 
+ * Notes: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
+ *        being activated 
+ *
+ *        Ideally consecutive SetWindowPos should be replaced by 
+ *        BeginDeferWindowPos/EndDeferWindowPos but currently it doesn't
+ *        matter.
+ *
+ *	  wTo is basically lParam of WM_MDINEXT message
  */
-HWND MDIDestroyChild(WND *w_parent, MDICLIENTINFO *ci, HWND parent,
-		     HWND child, BOOL flagDestroy)
+void MDI_SwitchActiveChild(HWND clientHwnd, HWND childHwnd, WORD wTo )
 {
-    MDICHILDINFO  *chi;
-    HLOCAL hinfo;
-    
-    hinfo = ci->infoActiveChildren;
-    while (hinfo != 0) {
-	chi = (MDICHILDINFO *)USER_HEAP_LIN_ADDR(hinfo);
-	if (chi->hwnd == child) break;
-	hinfo = chi->next;
-    }
-    
-    if (hinfo != 0)
-    {
-	if (chi->prev)
-	    ((MDICHILDINFO *)USER_HEAP_LIN_ADDR(chi->prev))->next = chi->next;
-	if (chi->next)
-	    ((MDICHILDINFO *)USER_HEAP_LIN_ADDR(chi->next))->prev = chi->prev;
-	if (ci->infoActiveChildren == hinfo)
-	    ci->infoActiveChildren = chi->next;
-
-	ci->nActiveChildren--;
-	
-	if (chi->hwnd == ci->hwndActiveChild)
-	    SendMessage(parent, WM_CHILDACTIVATE, 0, 0);
-
-	USER_HEAP_FREE(hinfo);
-	
-	if (flagDestroy)
-	    DestroyWindow(child);
-    }
-    
-    return 0;
-}
-
-/**********************************************************************
- *					MDIBringChildToTop
- */
-void MDIBringChildToTop(HWND parent, WORD id, WORD by_id, BOOL send_to_bottom)
-{
-    HLOCAL hinfo;
-    MDICHILDINFO  *chi;
+    WND		  *w	     = WIN_FindWndPtr(clientHwnd);
+    HWND	   hwndTo    = MDI_GetWindow(w,childHwnd,wTo);
+    HWND	   hwndPrev;
     MDICLIENTINFO *ci;
-    WND           *w;
-    int            i;
 
-    w  = WIN_FindWndPtr(parent);
-    ci = (MDICLIENTINFO *) w->wExtra;
     
-    dprintf_mdi(stddeb, "MDIBringToTop: id %04x, by_id %d\n", id, by_id);
+    ci = (MDICLIENTINFO *) w->wExtra;
 
-    if (by_id)
-	id -= ci->idFirstChild;
-    if (!by_id || id < ci->nActiveChildren)
-    {
-	hinfo = ci->infoActiveChildren;
+    dprintf_mdi(stddeb, "MDI_SwitchActiveChild: "NPFMT", %i\n",childHwnd,wTo);
 
-	if (by_id)
-	{
-	    for (i = 0; i < id; i++)
-		hinfo = ((MDICHILDINFO *)USER_HEAP_LIN_ADDR(hinfo))->next;
-	    chi = USER_HEAP_LIN_ADDR(hinfo);
-	}
-	else
-	{
-	    while (hinfo != 0) {
-		chi = (MDICHILDINFO *)USER_HEAP_LIN_ADDR(hinfo);
-		if (chi->hwnd == (HWND)id) break;
-	        hinfo = chi->next;
-	    }
-	}
+    if ( !childHwnd || !hwndTo ) return; 
 
-	if (hinfo == 0)
-	    return;
+    hwndPrev = ci->hwndActiveChild;
 
-	dprintf_mdi(stddeb, "MDIBringToTop: child "NPFMT"\n", chi->hwnd);
-	if (hinfo != ci->infoActiveChildren)
+    if ( hwndTo != hwndPrev )
 	{
 	    if (ci->flagChildMaximized)
 	    {
 		RECT rectOldRestore, rect;
 
-		w = WIN_FindWndPtr(chi->hwnd);
+		w = WIN_FindWndPtr(hwndTo);
 		
+		/* save old window dimensions */
 		rectOldRestore = ci->rectRestore;
-		GetWindowRect(chi->hwnd, &ci->rectRestore);
+		GetWindowRect(hwndTo, &ci->rectRestore);
 
 		rect.top    = (ci->rectMaximize.top -
 			       (w->rectClient.top - w->rectWindow.top));
@@ -244,61 +309,99 @@
 		rect.right  = (ci->rectMaximize.right +
 			       (w->rectWindow.right - w->rectClient.right));
 		w->dwStyle |= WS_MAXIMIZE;
-		SetWindowPos(chi->hwnd, HWND_TOP, rect.left, rect.top, 
+
+		/* maximize it */
+		ci->flagChildMaximized = childHwnd; /* prevent maximization
+						     * in MDI_ChildActivate
+						     */
+
+		SetWindowPos( hwndTo, HWND_TOP, rect.left, rect.top, 
 			     rect.right - rect.left + 1,
 			     rect.bottom - rect.top + 1, 0);
-		SendMessage(chi->hwnd, WM_SIZE, SIZE_MAXIMIZED,
+
+		SendMessage( hwndTo, WM_SIZE, SIZE_MAXIMIZED,
 			    MAKELONG(w->rectClient.right-w->rectClient.left,
 				     w->rectClient.bottom-w->rectClient.top));
 
-		w = WIN_FindWndPtr(ci->hwndActiveChild);
+		w = WIN_FindWndPtr(hwndPrev);
+
+	        if( w )
+		  {
 		w->dwStyle &= ~WS_MAXIMIZE;
-		SetWindowPos(ci->hwndActiveChild, HWND_BOTTOM, 
+
+		     /* push hwndPrev to the bottom if needed */
+		     if( !wTo )
+		         SetWindowPos(hwndPrev, HWND_BOTTOM, 
 			     rectOldRestore.left, rectOldRestore.top, 
 			     rectOldRestore.right - rectOldRestore.left + 1, 
 			     rectOldRestore.bottom - rectOldRestore.top + 1,
-			     SWP_NOACTIVATE | 
-			     (send_to_bottom ? 0 : SWP_NOZORDER));
+			          SWP_NOACTIVATE );
+	          }
 	    }
 	    else
 	    {
-		SetWindowPos(chi->hwnd, HWND_TOP, 0, 0, 0, 0, 
+		SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0, 
 			     SWP_NOMOVE | SWP_NOSIZE );
-		if (send_to_bottom)
+		if( !wTo && hwndPrev )
 		{
-		    SetWindowPos(ci->hwndActiveChild, HWND_BOTTOM, 0, 0, 0, 0, 
+		    SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0, 
 				 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
 		}
 	    }
+    }
 		
-	    if (chi->next)
-		((MDICHILDINFO *)USER_HEAP_LIN_ADDR(chi->next))->prev = chi->prev;
+}
 
-	    if (chi->prev)
-		((MDICHILDINFO *)USER_HEAP_LIN_ADDR(chi->prev))->next = chi->next;
 	    
-	    chi->prev              = 0;
-	    chi->next              = ci->infoActiveChildren;
-	    ((MDICHILDINFO *)USER_HEAP_LIN_ADDR(chi->next))->prev = hinfo;
-	    ci->infoActiveChildren = hinfo;
+/**********************************************************************
+ *                                      MDIDestroyChild
+ */
+HWND MDIDestroyChild(WND *w_parent, MDICLIENTINFO *ci, HWND parent,
+                     HWND child, BOOL flagDestroy)
+{
+    WND         *childPtr = WIN_FindWndPtr(child);
 
-	    SendMessage(parent, WM_CHILDACTIVATE, 0, 0);
+    if( childPtr )
+    {
+        if( child == ci->hwndActiveChild )
+          {
+	    MDI_SwitchActiveChild(parent,child,0);
+
+	    if( child == ci->hwndActiveChild )
+                MDI_ChildActivate(w_parent,0);
+
+	    MDI_MenuDeleteItem(w_parent, child);
 	}
 	
-	dprintf_mdi(stddeb, "MDIBringToTop: pos %04x, hwnd "NPFMT"\n", 
-		id, chi->hwnd);
+        ci->nActiveChildren--;
+
+        if( ci->flagChildMaximized == child )
+            ci->flagChildMaximized = 1;
+
+        if (flagDestroy)
+	   {
+            DestroyWindow(child);
+	    PostMessage(parent,WM_MDICALCCHILDSCROLL,0,0L);
+	    ci->sbRecalc |= (SB_BOTH+1);
+	   }
     }
+
+    return 0;
 }
 
+
 /**********************************************************************
  *					MDIMaximizeChild
  */
 LONG MDIMaximizeChild(HWND parent, HWND child, MDICLIENTINFO *ci)
 {
+
     WND *w = WIN_FindWndPtr(child);
     RECT rect;
     
-    MDIBringChildToTop(parent, child, FALSE, FALSE);
+    if( !SendMessage( child, WM_QUERYOPEN, 0, 0L) )
+	 return 0;
+    
     ci->rectRestore = w->rectWindow;
 
     rect.top    = (ci->rectMaximize.top -
@@ -310,15 +413,16 @@
     rect.right  = (ci->rectMaximize.right +
 		   (w->rectWindow.right - w->rectClient.right));
     w->dwStyle |= WS_MAXIMIZE;
+
     SetWindowPos(child, 0, rect.left, rect.top, 
-		 rect.right - rect.left + 1, rect.bottom - rect.top + 1,
-		 SWP_NOACTIVATE | SWP_NOZORDER);
+		 rect.right - rect.left + 1, rect.bottom - rect.top + 1, 0);
     
-    ci->flagChildMaximized = TRUE;
+    ci->flagChildMaximized = child;
     
     SendMessage(child, WM_SIZE, SIZE_MAXIMIZED,
 		MAKELONG(w->rectClient.right-w->rectClient.left,
 			 w->rectClient.bottom-w->rectClient.top));
+
     SendMessage(GetParent(parent), WM_NCPAINT, 0, 0);
 
     return 0;
@@ -329,64 +433,163 @@
  */
 LONG MDIRestoreChild(HWND parent, MDICLIENTINFO *ci)
 {
-    HWND    child;
+    HWND    hWnd;
 
-    dprintf_mdi(stddeb,"restoring mdi child\n");
+    hWnd = ci->hwndActiveChild;
 
-    child = ci->hwndActiveChild;
+    dprintf_mdi(stddeb,"MDIRestoreChild: restore "NPFMT"\n", hWnd);
+
     ci->flagChildMaximized = FALSE;
 
-    ShowWindow(child, SW_RESTORE);		/* display the window */
-    MDIBringChildToTop(parent, child, FALSE, FALSE);
-    SendMessage(GetParent(parent), WM_NCPAINT, 0, 0);
+    ShowWindow(hWnd, SW_RESTORE);		/* display the window */
+
+    hWnd = GetParent(parent);
+
+    SendMessage(hWnd,WM_NCPAINT , 0, 0);
 
     return 0;
 }
 
 /**********************************************************************
- *					MDIChildActivated
+ *					MDI_ChildActivate
+ *
+ * Note: hWndChild is NULL when last child is being destroyed
  */
-LONG MDIChildActivated(WND *w, MDICLIENTINFO *ci, HWND parent)
+LONG MDI_ChildActivate(WND *clientPtr, HWND hWndChild)
 {
-    HLOCAL hinfo;
-    MDICHILDINFO *chi;
-    HWND          deact_hwnd;
-    HWND          act_hwnd;
-    LONG          lParam;
+    MDICLIENTINFO       *clientInfo = (MDICLIENTINFO*)clientPtr->wExtra; 
+    HWND                 prevActiveWnd = clientInfo->hwndActiveChild;
+    WND                 *wndPtr = WIN_FindWndPtr( hWndChild );
+    WND			*wndPrev = WIN_FindWndPtr( prevActiveWnd );
+    BOOL		 isActiveFrameWnd = 0;	 
 
-    dprintf_mdi(stddeb, "MDIChildActivate: top "NPFMT"\n", w->hwndChild);
+    if( hWndChild == prevActiveWnd ) return 0L;
 
-    hinfo = ci->infoActiveChildren;
-    if (hinfo)
+    if( wndPtr )
+        if( wndPtr->dwStyle & WS_DISABLED ) return 0L;
+
+    dprintf_mdi(stddeb,"MDI_ChildActivate: "NPFMT"\n", hWndChild);
+
+    if( GetActiveWindow() == clientPtr->hwndParent )
+        isActiveFrameWnd = TRUE;
+	
+    /* deactivate prev. active child */
+    if( wndPrev )
     {
-	chi = (MDICHILDINFO *)USER_HEAP_LIN_ADDR(hinfo);
-	deact_hwnd = ci->hwndActiveChild;
-	act_hwnd   = chi->hwnd;                /* FIX: Hack */
-	lParam     = ((LONG) deact_hwnd << 16) | (LONG)act_hwnd;
+	SendMessage( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
+        SendMessage( prevActiveWnd, WM_MDIACTIVATE, FALSE,
+					    MAKELONG(hWndChild,prevActiveWnd));
+        /* uncheck menu item */
+       	if( clientInfo->hWindowMenu )
+       	        CheckMenuItem( clientInfo->hWindowMenu,
+       	                       wndPrev->wIDmenu, 0);
+      }
 
-	dprintf_mdi(stddeb, "MDIChildActivate: deact "NPFMT", act "NPFMT"\n",
-	       deact_hwnd, act_hwnd);
+    /* set appearance */
+    if( clientInfo->flagChildMaximized )
+      if( clientInfo->flagChildMaximized != hWndChild )
+        if( hWndChild )
+	        {
+		  clientInfo->hwndActiveChild = hWndChild;
+		  MDIMaximizeChild(GetParent(hWndChild),hWndChild,clientInfo);
+	        }
 
-	ci->hwndActiveChild = act_hwnd;
+    clientInfo->hwndActiveChild = hWndChild;
 
-	if (deact_hwnd != act_hwnd)
+    /* check if we have any children left */
+    if( !hWndChild )
 	{
-	    MDIRecreateMenuList(ci);
-	    SendMessage(deact_hwnd,  WM_NCACTIVATE, FALSE, 0);
-	    SendMessage(deact_hwnd, WM_MDIACTIVATE, FALSE, lParam);
+	    if( isActiveFrameWnd )
+		SetFocus( GetParent(hWndChild) );
+	    return 0;
 	}
 	
-	SendMessage(act_hwnd,  WM_NCACTIVATE, TRUE, 0);
-	SendMessage(act_hwnd, WM_MDIACTIVATE, TRUE, lParam);
+    /* check menu item */
+    if( clientInfo->hWindowMenu )
+              CheckMenuItem( clientInfo->hWindowMenu,
+                             wndPtr->wIDmenu, MF_CHECKED);
+
+    /* bring active child to the top */
+    SetWindowPos( hWndChild, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+
+    if( isActiveFrameWnd )
+	  {
+	    SendMessage( hWndChild, WM_NCACTIVATE, TRUE, 0L);
+	    if( GetFocus() == GetParent(hWndChild) )
+		SendMessage( GetParent(hWndChild), WM_SETFOCUS, 
+			     GetParent(hWndChild), 0L );
+	    else
+		SetFocus( GetParent(hWndChild) );
     }
 
-    if (hinfo || ci->nActiveChildren == 0)
+    SendMessage( hWndChild, WM_MDIACTIVATE, TRUE,
+				       MAKELONG(prevActiveWnd,hWndChild) );
+
+    return 1;
+}
+
+/**********************************************************************
+ *			MDI_BuildWCL
+ *
+ *  iTotal returns number of children available for tiling or cascading
+ */
+MDIWCL* MDI_BuildWCL(WND* clientWnd, int* iTotal)
+{
+    MDIWCL *listTop,*listNext;
+    WND    *childWnd;
+
+    if (!(listTop = (MDIWCL*)malloc( sizeof(MDIWCL) ))) return NULL;
+
+    listTop->hChild = clientWnd->hwndChild;
+    listTop->prev   = NULL;
+    *iTotal 	    = 1;
+
+    /* build linked list from top child to bottom */
+
+    childWnd  =  WIN_FindWndPtr( listTop->hChild );
+    while( childWnd && childWnd->hwndNext )
     {
-	MDIRecreateMenuList(ci);
-	SendMessage(GetParent(parent), WM_NCPAINT, 0, 0);
-    }
+	listNext = (MDIWCL*)malloc(sizeof(MDIWCL));
+	
+	if( !listNext )
+	{
+	    /* quit gracefully */
+	    listNext = listTop->prev;
+	    while( listTop )
+	    {
+                listNext = listTop->prev;
+                free(listTop);
+                listTop  = listNext;
+	    }
+	    fprintf(stdnimp,"MDICascade: allocation failed\n");
+	    return NULL;
+	}
     
-    return 0;
+	if( (childWnd->dwStyle & WS_DISABLED) ||
+	    (childWnd->dwStyle & WS_MINIMIZE) ||
+	    !(childWnd->dwStyle & WS_VISIBLE)   )
+	{
+	    listTop->hChild = 0;
+	    (*iTotal)--;
+	}
+
+	listNext->hChild = childWnd->hwndNext;
+	listNext->prev   = listTop;
+	listTop          = listNext;
+	(*iTotal)++;
+
+	childWnd  =  WIN_FindWndPtr( childWnd->hwndNext );
+    }
+
+    if( (childWnd->dwStyle & WS_DISABLED) ||
+	(childWnd->dwStyle & WS_MINIMIZE) ||
+	!(childWnd->dwStyle & WS_VISIBLE)   )
+    {
+	listTop->hChild = 0;
+	(*iTotal)--;
+    }
+ 
+    return listTop;
 }
 
 /**********************************************************************
@@ -394,19 +597,17 @@
  */
 LONG MDICascade(HWND parent, MDICLIENTINFO *ci)
 {
-    HLOCAL hinfo;
-    MDICHILDINFO *chi;
+    WND		 *clientWnd;
+    MDIWCL	 *listTop,*listPrev;
     RECT          rect;
     int           spacing, xsize, ysize;
     int		  x, y;
+    int		  iToPosition = 0;
 
     if (ci->flagChildMaximized)
 	MDIRestoreChild(parent, ci);
 
-    /* If there aren't any children, don't even bother.
-     */
-    if (ci->nActiveChildren == 0)
-        return 0;
+    if (ci->nActiveChildren == 0) return 0;
 
     GetClientRect(parent, &rect);
     spacing = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME);
@@ -417,30 +618,34 @@
       "MDICascade: Client wnd at (%ld,%ld) - (%ld,%ld), spacing %d\n", 
       (LONG)rect.left, (LONG)rect.top, (LONG)rect.right, (LONG)rect.bottom,
       spacing);
-    dprintf_mdi(stddeb, "MDICascade: searching for last child\n");
-    hinfo = ci->infoActiveChildren;
-    while(1) {
-	chi = USER_HEAP_LIN_ADDR(hinfo);
-	if (chi->next == 0) break;
-	hinfo = chi->next;
-    }
     
-    dprintf_mdi(stddeb, "MDICascade: last child is "NPFMT"\n", chi->hwnd);
+    clientWnd =  WIN_FindWndPtr( parent );
+
+    listTop   =  MDI_BuildWCL(clientWnd,&iToPosition); 
+
+    if( !listTop ) return 0;
+
     x = 0;
     y = 0;
-    while (hinfo != 0)
+
+    /* walk list and move windows */
+    while ( listTop )
     {
-	chi = USER_HEAP_LIN_ADDR(hinfo);
 	dprintf_mdi(stddeb, "MDICascade: move "NPFMT" to (%d,%d) size [%d,%d]\n", 
-		chi->hwnd, x, y, xsize, ysize);
-        if (IsIconic(chi->hwnd)) continue;
-	SetWindowPos(chi->hwnd, 0, x, y, xsize, ysize, 
+		listTop->hChild, x, y, xsize, ysize);
+
+	if( listTop->hChild )
+          {
+	   SetWindowPos(listTop->hChild, 0, x, y, xsize, ysize, 
 		     SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
 
 	x += spacing;
 	y += spacing;
+	  }
 	
-	hinfo = chi->prev;
+	listPrev = listTop->prev;
+	free(listTop);
+	listTop = listPrev;
     }
 
     return 0;
@@ -448,57 +653,84 @@
 
 /**********************************************************************
  *					MDITile
+ *
  */
 LONG MDITile(HWND parent, MDICLIENTINFO *ci)
 {
-    HLOCAL hinfo;
-    MDICHILDINFO *chi;
+    WND		 *wndClient = WIN_FindWndPtr(parent);
+    MDIWCL       *listTop,*listPrev;
     RECT          rect;
     int           xsize, ysize;
     int		  x, y;
     int		  rows, columns;
     int           r, c;
     int           i;
+    int		  iToPosition = 0;
 
     if (ci->flagChildMaximized)
 	MDIRestoreChild(parent, ci);
 
-    /* If there aren't any children, don't even bother.
-     */
-    if (ci->nActiveChildren == 0)
-        return 0;
+    if (ci->nActiveChildren == 0) return 0;
+
+    listTop = MDI_BuildWCL(wndClient, &iToPosition);
+
+    dprintf_mdi(stddeb,"MDITile: %i windows to tile\n",iToPosition);
+
+    if( !listTop ) return 0;
 
     GetClientRect(parent, &rect);
-    rows    = (int) sqrt((double) ci->nActiveChildren);
-    columns = ci->nActiveChildren / rows;
+
+    rows    = (int) sqrt((double) iToPosition);
+    columns = iToPosition / rows;
+
+    /* hack */
+    if( iToPosition != ci->nActiveChildren)
+        {
+           y = rect.bottom - 2 * SYSMETRICS_CYICONSPACING - SYSMETRICS_CYICON;
+           rect.bottom = ( y - SYSMETRICS_CYICON < rect.top )? rect.bottom: y;
+	}
+
     ysize   = rect.bottom / rows;
     xsize   = rect.right  / columns;
     
-    hinfo   = ci->infoActiveChildren;
     x       = 0;
     i       = 0;
+
     for (c = 1; c <= columns; c++)
     {
 	if (c == columns)
 	{
-	    rows  = ci->nActiveChildren - i;
+	    rows  = iToPosition - i;
 	    ysize = rect.bottom / rows;
 	}
 
 	y = 0;
 	for (r = 1; r <= rows; r++, i++)
 	{
-	    chi = (MDICHILDINFO *)USER_HEAP_LIN_ADDR(hinfo);
-	    SetWindowPos(chi->hwnd, 0, x, y, xsize, ysize, 
-			 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
+	    /* shouldn't happen but... */
+	    if( !listTop )
+		 break;
 
+	    if( listTop->hChild )
+		{
+	            SetWindowPos(listTop->hChild, 0, x, y, xsize, ysize, 
+			 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
 	    y += ysize;
-	    hinfo = chi->next;
+		}
+
+            listPrev = listTop->prev;
+            free(listTop);
+            listTop = listPrev;
 	}
 
 	x += xsize;
     }
     
+    /* free the rest if any */
+    while( listTop ) {
+	 listPrev = listTop->prev;
+	 free(listTop);
+	 listTop = listPrev; }
 
     return 0;
 }
@@ -630,19 +862,18 @@
     
     switch (message)
     {
-      case WM_CHILDACTIVATE:
-	return MDIChildActivated(w, ci, hwnd);
-
       case WM_CREATE:
 	cs                      = (LPCREATESTRUCT) PTR_SEG_TO_LIN(lParam);
 	ccs                     = (LPCLIENTCREATESTRUCT) PTR_SEG_TO_LIN(cs->lpCreateParams);
 	ci->hWindowMenu         = ccs->hWindowMenu;
 	ci->idFirstChild        = ccs->idFirstChild;
-	ci->infoActiveChildren  = 0;
-	ci->flagMenuAltered     = FALSE;
 	ci->flagChildMaximized  = FALSE;
+	ci->sbStop		= 0;
+
 	w->dwStyle             |= WS_CLIPCHILDREN;
 
+	AppendMenu(ccs->hWindowMenu,MF_SEPARATOR,0,NULL);
+
 	GetClientRect(w->hwndParent, &ci->rectMaximize);
 	MoveWindow(hwnd, 0, 0, 
 		   ci->rectMaximize.right, ci->rectMaximize.bottom, 1);
@@ -650,7 +881,7 @@
 	return 0;
 
       case WM_MDIACTIVATE:
-	MDIBringChildToTop(hwnd, wParam, FALSE, FALSE);
+	SetWindowPos(wParam,0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
 	return 0;
 
       case WM_MDICASCADE:
@@ -664,16 +895,20 @@
 
       case WM_MDIGETACTIVE:
 	return ((LONG) ci->hwndActiveChild | 
-		((LONG) ci->flagChildMaximized << 16));
+		((LONG) (ci->flagChildMaximized>0) << 16));
 
       case WM_MDIICONARRANGE:
-	return MDIIconArrange(hwnd);
+	       ci->sbStop = TRUE;
+	       MDIIconArrange(hwnd);
+	       ci->sbStop = FALSE;
+	       SendMessage(hwnd,WM_MDICALCCHILDSCROLL,0,0L);
+	       return 0;
 	
       case WM_MDIMAXIMIZE:
 	return MDIMaximizeChild(hwnd, wParam, ci);
 
       case WM_MDINEXT:
-	MDIBringChildToTop(hwnd, wParam, FALSE, TRUE);
+	MDI_SwitchActiveChild(hwnd, (HWND)wParam, lParam);
 	break;
 	
       case WM_MDIRESTORE:
@@ -683,27 +918,55 @@
 	return MDISetMenu(hwnd, wParam, LOWORD(lParam), HIWORD(lParam));
 	
       case WM_MDITILE:
-	return MDITile(hwnd, ci);
+	ci->sbStop = TRUE;
+	ShowScrollBar(hwnd,SB_BOTH,FALSE);
+	MDITile(hwnd, ci);
+        ci->sbStop = FALSE;
+        return 0;
+
+      case WM_VSCROLL:
+      case WM_HSCROLL:
+	ci->sbStop = TRUE;
+        ScrollChildren(hwnd,message,wParam,lParam);
+	ci->sbStop = FALSE;
+        return 0;
+
+      case WM_SETFOCUS:
+	if( ci->hwndActiveChild )
+	  {
+	   w = WIN_FindWndPtr( ci->hwndActiveChild );
+	   if( !(w->dwStyle & WS_MINIMIZE) )
+	       SetFocus( ci->hwndActiveChild );
+	  } 
+	return 0;
 	
       case WM_NCACTIVATE:
+        if( ci->hwndActiveChild )
 	SendMessage(ci->hwndActiveChild, message, wParam, lParam);
 	break;
 	
       case WM_PARENTNOTIFY:
-	if (wParam == WM_DESTROY)
-#ifdef WINELIB32
-	    return MDIDestroyChild(w, ci, hwnd, lParam, FALSE);
-#else
-	    return MDIDestroyChild(w, ci, hwnd, LOWORD(lParam), FALSE);
-#endif
-	else if (wParam == WM_LBUTTONDOWN)
-	    MDIBringChildToTop(hwnd, ci->hwndHitTest, FALSE, FALSE);
+	if (wParam == WM_LBUTTONDOWN)
+	     SetWindowPos(ci->hwndHitTest, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
 	break;
 
       case WM_SIZE:
 	GetClientRect(w->hwndParent, &ci->rectMaximize);
+	if( !ci->hwndActiveChild )
+	  {
+	     PostMessage(hwnd,WM_MDICALCCHILDSCROLL,0,0L);
+	     ci->sbRecalc |= (SB_BOTH+1);
+	  }
 	break;
 
+      case WM_MDICALCCHILDSCROLL:
+	if( !ci->sbStop )
+	  if( ci->sbRecalc )
+	    {
+	      CalcChildScroll(hwnd, ci->sbRecalc-1);
+	      ci->sbRecalc = 0;
+	    }
+	return 0;
     }
     
     return DefWindowProc(hwnd, message, wParam, lParam);
@@ -716,12 +979,17 @@
 LRESULT DefFrameProc(HWND hwnd, HWND hwndMDIClient, UINT message, 
 		     WPARAM wParam, LPARAM lParam)
 {
+    HWND	childHwnd;
+
     if (hwndMDIClient)
     {
 	switch (message)
 	{
 	  case WM_COMMAND:
-	    MDIBringChildToTop(hwndMDIClient, wParam, TRUE, FALSE);
+	    childHwnd = MDI_GetChildByID( WIN_FindWndPtr(hwndMDIClient),
+                                          wParam );
+ 	    if( childHwnd )
+	        SendMessage(hwndMDIClient, WM_MDIACTIVATE, childHwnd , 0L);
 	    break;
 
 	  case WM_NCLBUTTONDOWN:
@@ -739,7 +1007,7 @@
 				     message, wParam, lParam);
 	
 	  case WM_SETFOCUS:
-	    SendMessage(hwndMDIClient, WM_SETFOCUS, wParam, lParam);
+	    SetFocus(hwndMDIClient);
 	    break;
 
 	  case WM_SIZE:
@@ -763,10 +1031,10 @@
 #endif
 {
     MDICLIENTINFO       *ci;
-    WND                 *w;
+    WND                 *clientWnd;
 
-    w  = WIN_FindWndPtr(GetParent(hwnd));
-    ci = (MDICLIENTINFO *) w->wExtra;
+    clientWnd  = WIN_FindWndPtr(GetParent(hwnd));
+    ci         = (MDICLIENTINFO *) clientWnd->wExtra;
     
     switch (message)
     {
@@ -774,10 +1042,29 @@
 	ci->hwndHitTest = hwnd;
 	break;
 	
-      case WM_NCPAINT:
-	NC_DoNCPaint( hwnd, hwnd == ci->hwndActiveChild, FALSE );
+      case WM_SETTEXT:
+	DefWindowProc(hwnd, message, wParam, lParam);
+	MDI_MenuModifyItem(clientWnd,hwnd);
         return 0;
 
+      case WM_CLOSE:
+	SendMessage(GetParent(hwnd),WM_MDIDESTROY,hwnd,0L);
+	return 0;
+
+      case WM_SIZE:
+	if( ci->hwndActiveChild != hwnd )
+	    MDI_ChildActivate(clientWnd, hwnd);
+	break;
+
+      case WM_CHILDACTIVATE:
+	MDI_ChildActivate(clientWnd, hwnd);
+	return 0;
+
+      case WM_NCPAINT:
+	dprintf_mdi(stddeb,"DefMDIChildProc: WM_NCPAINT for "NPFMT", active "NPFMT"\n",
+					     hwnd, ci->hwndActiveChild );
+	break;
+
       case WM_SYSCOMMAND:
 	switch (wParam)
 	{
@@ -789,6 +1076,34 @@
 	}
 	break;
 	
+      /* should also handle following messages */
+      case WM_GETMINMAXINFO:
+	   /* should return rect of MDI client 
+	    * so that normal ShowWindow will be able to handle
+	    * actions that are handled by MDIMaximize and MDIRestore */
+
+      case WM_SETVISIBLE:
+         if( !ci->sbStop )
+          {
+            PostMessage(GetParent(hwnd),WM_MDICALCCHILDSCROLL,0,0L);
+            ci->sbRecalc |= (SB_BOTH+1);
+          }
+	break;
+      case WM_SETFOCUS:
+	if( IsChild( GetActiveWindow(), GetParent(hwnd)) )
+	    SendMessage(clientWnd->hwndChild,WM_CHILDACTIVATE,0,0L);
+        if( !ci->sbStop )
+          {
+            PostMessage(GetParent(hwnd),WM_MDICALCCHILDSCROLL,0,0L);
+            ci->sbRecalc |= (SB_BOTH+1);
+          }
+	break;
+
+      case WM_MENUCHAR:
+      case WM_NEXTMENU:
+	   /* set current menu to child system menu */
+
+	break;	
     }
 	
     return DefWindowProc(hwnd, message, wParam, lParam);
@@ -836,3 +1151,81 @@
         SetScrollPos( hwnd, SB_HORZ, clientRect.top - childRect.top, TRUE );
     }
 }
+
+/***********************************************************************
+ *           ScrollChildren   (USER.463)
+ */
+void ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ WND	*wndPtr = WIN_FindWndPtr(hWnd);
+ short 	 newPos;
+ short 	 curPos;
+ short 	 length;
+ short 	 minPos;
+ short 	 maxPos;
+ short   shift;
+
+ if( !wndPtr ) return;
+
+ if( uMsg == WM_HSCROLL )
+   {
+     GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
+     curPos = GetScrollPos(hWnd,SB_HORZ);
+     length = (wndPtr->rectClient.right - wndPtr->rectClient.left)/2;
+     shift = SYSMETRICS_CYHSCROLL;
+   }
+ else if( uMsg == WM_VSCROLL )
+	{
+	  GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
+	  curPos = GetScrollPos(hWnd,SB_VERT);
+	  length = (wndPtr->rectClient.bottom - wndPtr->rectClient.top)/2;
+	  shift = SYSMETRICS_CXVSCROLL;
+	}
+      else return;
+
+ switch( wParam )
+   {
+	case SB_LINEUP:	
+		        newPos = curPos - shift;
+			break;
+	case SB_LINEDOWN:    
+			newPos = curPos + shift;
+			break;
+	case SB_PAGEUP:	
+			newPos = curPos - length;
+			break;
+	case SB_PAGEDOWN:    
+			newPos = curPos + length;
+			break;
+
+	case SB_THUMBPOSITION: 
+			newPos = LOWORD(lParam);
+			break;
+
+	case SB_THUMBTRACK:  
+			return;
+
+	case SB_TOP:		
+			newPos = minPos;
+			break;
+	case SB_BOTTOM:	
+			newPos = maxPos;
+			break;
+	case SB_ENDSCROLL:
+			CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
+			return;
+   }
+
+ if( newPos > maxPos )
+     newPos = maxPos;
+ else if( newPos < minPos )
+	  newPos = minPos;
+
+ SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
+
+ if( uMsg == WM_VSCROLL )
+     ScrollWindow(hWnd ,0 ,curPos - newPos, NULL, NULL);
+ else
+     ScrollWindow(hWnd ,curPos - newPos, 0, NULL, NULL);
+}
+