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);
+}
+