Replace GetModuleHandle("user32.dll") with User32Instance.
[reactos.git] / reactos / lib / user32 / windows / mdi.c
index 498e521..9078133 100644 (file)
  *
  */
 
-#include <stdlib.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-
-#include "windef.h"
-#include "winbase.h"
-#include "wingdi.h"
-#include "winuser.h"
-#include "wine/unicode.h"
-#include "user32/regcontrol.h"
-#include <winnls.h>
-#include "wine/debug.h"
-#include "dlgs.h"
+#include <user32.h>
+#define NDEBUG
+#include <debug.h>
+
 
 WINE_DEFAULT_DEBUG_CHANNEL(mdi);
 
@@ -141,6 +130,47 @@ static void MDI_SwapMenuItems(HWND, UINT, UINT);
 static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
 static LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
 
+
+static
+HWND* WIN_ListChildren (HWND hWndparent)
+{
+
+  DWORD dwCount = 0;
+  HWND* pHwnd = NULL;
+  HANDLE hHeap;
+
+  SetLastError(0);
+
+  dwCount = NtUserBuildHwndList ( NULL, hWndparent, FALSE, 0, 0, NULL, 0 );
+
+  if ( !dwCount || GetLastError() )
+    return 0;
+
+  /* allocate buffer to receive HWND handles */
+  hHeap = GetProcessHeap();
+
+  pHwnd = HeapAlloc ( hHeap, 0, sizeof(HWND)*(dwCount+1) );
+  if ( !pHwnd )
+    {
+      SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
+      return 0;
+    }
+
+  /* now call kernel again to fill the buffer this time */
+  dwCount = NtUserBuildHwndList (NULL, hWndparent, FALSE, 0, 0, pHwnd, dwCount );
+
+  if ( !dwCount || GetLastError() )
+    {
+      if ( pHwnd )
+       HeapFree ( hHeap, 0, pHwnd );
+      return 0;
+    }
+
+  return pHwnd;
+}
+
+
+
 #ifdef __REACTOS__
 void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
 void WINAPI CalcChildScroll(HWND hwnd, INT scroll);
@@ -149,8 +179,8 @@ BOOL CALLBACK MDI_GetChildByID_EnumProc (HWND hwnd, LPARAM lParam )
 {
     DWORD *control = (DWORD *)lParam;
     if(*control == GetWindowLongW( hwnd, GWL_ID ))
-    {        
-        *control = (DWORD)hwnd;        
+    {
+        *control = (DWORD)hwnd;
         return FALSE;
     }
     return TRUE;
@@ -165,7 +195,7 @@ static HWND MDI_GetChildByID(HWND hwnd, UINT id)
 {
 #ifdef __REACTOS__
     DWORD Control = id;
-    if (hwnd && !EnumChildWindows(hwnd, (ENUMWINDOWSPROC)&MDI_GetChildByID_EnumProc, (LPARAM)&Control))
+    if (hwnd && !EnumChildWindows(hwnd, (WNDENUMPROC)&MDI_GetChildByID_EnumProc, (LPARAM)&Control))
     {
         return (HWND)Control;
     }
@@ -234,6 +264,20 @@ static MDICLIENTINFO *get_client_info( HWND client )
 #endif
 }
 
+static BOOL is_close_enabled(HWND hwnd, HMENU hSysMenu)
+{
+    if (GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE) return FALSE;
+
+    if (!hSysMenu) hSysMenu = GetSystemMenu(hwnd, FALSE);
+    if (hSysMenu)
+    {
+        UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
+        if (state == 0xFFFFFFFF || (state & (MF_DISABLED | MF_GRAYED)))
+            return FALSE;
+    }
+    return TRUE;
+}
+
 /**********************************************************************
  *                     MDI_MenuModifyItem
  */
@@ -305,7 +349,7 @@ static BOOL MDI_MenuDeleteItem( HWND client, HWND hWndChild )
     if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
     {
         WCHAR szTmp[50];
-        LoadStringW(GetModuleHandleA("USER32"), IDS_MDI_MOREWINDOWS, szTmp, sizeof(szTmp)/sizeof(szTmp[0]));
+        LoadStringW(User32Instance, IDS_MDI_MOREWINDOWS, szTmp, sizeof(szTmp)/sizeof(szTmp[0]));
         AppendMenuW(clientInfo->hWindowMenu, MF_STRING, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp);
     }
     return TRUE;
@@ -319,10 +363,6 @@ static BOOL MDI_MenuDeleteItem( HWND client, HWND hWndChild )
 static HWND MDI_GetWindow(MDICLIENTINFO *clientInfo, HWND hWnd, BOOL bNext,
                             DWORD dwStyleMask )
 {
-#ifdef __REACTOS__
-    /* FIXME */
-    return 0;
-#else
     int i;
     HWND *list;
     HWND last = 0;
@@ -354,7 +394,6 @@ static HWND MDI_GetWindow(MDICLIENTINFO *clientInfo, HWND hWnd, BOOL bNext,
  found:
     HeapFree( GetProcessHeap(), 0, list );
     return last;
-#endif
 }
 
 /**********************************************************************
@@ -641,7 +680,7 @@ static HWND MDICreateChild( HWND parent, MDICLIENTINFO *ci,
         if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
         {
             WCHAR szTmp[50];
-            LoadStringW(GetModuleHandleA("USER32"), IDS_MDI_MOREWINDOWS, szTmp, sizeof(szTmp)/sizeof(szTmp[0]));
+            LoadStringW(User32Instance, IDS_MDI_MOREWINDOWS, szTmp, sizeof(szTmp)/sizeof(szTmp[0]));
 
             ModifyMenuW(ci->hWindowMenu,
                         ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
@@ -910,19 +949,20 @@ static HBITMAP CreateMDIMenuBitmap(void)
  return hbCopy;
 }
 
+                    
+
+
 /**********************************************************************
  *                             MDICascade
  */
 static LONG MDICascade( HWND client, MDICLIENTINFO *ci )
 {
-#ifdef __REACTOS__
-    /* FIXME */
-    return 0;
-#else
     HWND *win_array;
     BOOL has_icons = FALSE;
     int i, total;
 
+DbgPrint("MDICascade\n");
+
     if (ci->hwndChildMaximized)
         SendMessageA( client, WM_MDIRESTORE,
                         (WPARAM)ci->hwndChildMaximized, 0);
@@ -966,7 +1006,6 @@ static LONG MDICascade( HWND client, MDICLIENTINFO *ci )
 
     if (has_icons) ArrangeIconicWindows( client );
     return 0;
-#endif
 }
 
 /**********************************************************************
@@ -974,14 +1013,12 @@ static LONG MDICascade( HWND client, MDICLIENTINFO *ci )
  */
 static void MDITile( HWND client, MDICLIENTINFO *ci, WPARAM wParam )
 {
-#ifdef __REACTOS__
-    /* FIXME */
-    return;
-#else
     HWND *win_array;
     int i, total;
     BOOL has_icons = FALSE;
 
+DbgPrint("MDITile\n");
+
     if (ci->hwndChildMaximized)
         SendMessageA( client, WM_MDIRESTORE, (WPARAM)ci->hwndChildMaximized, 0);
 
@@ -1054,7 +1091,6 @@ static void MDITile( HWND client, MDICLIENTINFO *ci, WPARAM wParam )
     }
     HeapFree( GetProcessHeap(), 0, win_array );
     if (has_icons) ArrangeIconicWindows( client );
-#endif
 }
 
 /* ----------------------- Frame window ---------------------------- */
@@ -1066,46 +1102,40 @@ static void MDITile( HWND client, MDICLIENTINFO *ci, WPARAM wParam )
 static BOOL MDI_AugmentFrameMenu( HWND frame, HWND hChild )
 {
     HMENU menu = GetMenu( frame );
-#ifndef __REACTOS__
-    WND*       child = WIN_FindWndPtr(hChild);
-#endif
     HMENU      hSysPopup = 0;
     HBITMAP hSysMenuBitmap = 0;
+    INT nItems;
+    UINT iId;
+    HICON hIcon;
 
     TRACE("frame %p,child %p\n",frame,hChild);
 
-#ifndef __REACTOS__
-    if( !menu || !child->hSysMenu )
-    {
-        WIN_ReleaseWndPtr(child);
-        return 0;
-    }
-    WIN_ReleaseWndPtr(child);
-#else
-    if( !menu || !GetSystemMenu(hChild, FALSE) )
-    {
+    if( !menu ) return 0;
+
+    /* if the system buttons already exist do not add them again */
+    nItems = GetMenuItemCount(menu) - 1;
+    iId = GetMenuItemID(menu,nItems) ;
+    if (iId == SC_RESTORE || iId == SC_CLOSE)
         return 0;
-    }
-#endif
 
     /* create a copy of sysmenu popup and insert it into frame menu bar */
-
-    if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
+    if (!(hSysPopup = GetSystemMenu(hChild, FALSE)))
        return 0;
 
-    AppendMenuA(menu,MF_HELP | MF_BITMAP,
-                   SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
-    AppendMenuA(menu,MF_HELP | MF_BITMAP,
-                   SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
+    AppendMenuW(menu, MF_HELP | MF_BITMAP,
+                SC_MINIMIZE, (LPCWSTR)HBMMENU_MBAR_MINIMIZE ) ;
+    AppendMenuW(menu, MF_HELP | MF_BITMAP,
+                SC_RESTORE, (LPCWSTR)HBMMENU_MBAR_RESTORE );
+    AppendMenuW(menu, MF_HELP | MF_BITMAP,
+                SC_CLOSE, is_close_enabled(hChild, hSysPopup) ?
+                (LPCWSTR)HBMMENU_MBAR_CLOSE : (LPCWSTR)HBMMENU_MBAR_CLOSE_D );
 
-  /* In Win 95 look, the system menu is replaced by the child icon */
-#ifndef __REACTOS__
-  if(TWEAK_WineLook > WIN31_LOOK)
-#endif
-  {
-    HICON hIcon = (HICON)GetClassLongA(hChild, GCL_HICONSM);
+    /* The system menu is replaced by the child icon */
+    hIcon = (HICON)GetClassLongW(hChild, GCL_HICONSM);
     if (!hIcon)
-      hIcon = (HICON)GetClassLongA(hChild, GCL_HICON);
+        hIcon = (HICON)GetClassLongW(hChild, GCL_HICON);
+    if (!hIcon)
+        hIcon = LoadIconW(NULL, IDI_APPLICATION);
     if (hIcon)
     {
       HDC hMemDC;
@@ -1131,11 +1161,6 @@ static BOOL MDI_AugmentFrameMenu( HWND frame, HWND hChild )
         hSysMenuBitmap = hBitmap;
       }
     }
-  }
-#ifndef __REACTOS__
-  else
-    hSysMenuBitmap = hBmpClose;
-#endif
 
     if( !InsertMenuA(menu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
                      (UINT_PTR)hSysPopup, (LPSTR)hSysMenuBitmap))
@@ -1145,15 +1170,6 @@ static BOOL MDI_AugmentFrameMenu( HWND frame, HWND hChild )
        return 0;
     }
 
-    /* The close button is only present in Win 95 look */
-#ifndef __REACTOS__
-    if(TWEAK_WineLook > WIN31_LOOK)
-#endif
-    {
-        AppendMenuA(menu,MF_HELP | MF_BITMAP,
-                       SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
-    }
-
     EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
     EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
     EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
@@ -1186,7 +1202,7 @@ static BOOL MDI_RestoreFrameMenu( HWND frame, HWND hChild )
      */
     memset(&menuInfo, 0, sizeof(menuInfo));
     menuInfo.cbSize = sizeof(menuInfo);
-    menuInfo.fMask  = MIIM_DATA | MIIM_TYPE;
+    menuInfo.fMask  = MIIM_DATA | MIIM_TYPE | MIIM_BITMAP;
 
     GetMenuItemInfoW(menu,
                     0,
@@ -1195,28 +1211,11 @@ static BOOL MDI_RestoreFrameMenu( HWND frame, HWND hChild )
 
     RemoveMenu(menu,0,MF_BYPOSITION);
 
-#ifndef __REACTOS__
-    if ( (menuInfo.fType & MFT_BITMAP)           &&
-        (LOWORD(menuInfo.dwTypeData)!=0)        &&
-        (LOWORD(menuInfo.dwTypeData)!=HBITMAP_16(hBmpClose)) )
-    {
-        DeleteObject(HBITMAP_32(LOWORD(menuInfo.dwTypeData)));
-    }
-#else
-    if ( (menuInfo.fType & MFT_BITMAP)           &&
-        (LOWORD(menuInfo.dwTypeData)!=0))
-    {
-        DeleteObject((HBITMAP)(LOWORD(menuInfo.dwTypeData) & 0x50000));
-    }
-#endif
+    if ( menuInfo.hbmpItem != 0 )
+        DeleteObject(menuInfo.hbmpItem);
 
-#ifndef __REACTOS__
-    if(TWEAK_WineLook > WIN31_LOOK)
-#endif
-    {
-        /* close */
-        DeleteMenu(menu,GetMenuItemCount(menu) - 1,MF_BYPOSITION);
-    }
+    /* close */
+    DeleteMenu(menu,GetMenuItemCount(menu) - 1,MF_BYPOSITION);
     /* restore */
     DeleteMenu(menu,GetMenuItemCount(menu) - 1,MF_BYPOSITION);
     /* minimize */
@@ -1307,7 +1306,7 @@ static LRESULT MDIClientWndProc_common( HWND hwnd, UINT message,
 {
     MDICLIENTINFO *ci = NULL;
 
-    if (WM_NCCREATE != message && WM_CREATE != message
+    if (WM_NCCREATE != message
         && NULL == (ci = get_client_info(hwnd)))
     {
         return 0;
@@ -1322,7 +1321,7 @@ static LRESULT MDIClientWndProc_common( HWND hwnd, UINT message,
         SetWindowLongPtrW( hwnd, 0, (LONG_PTR)ci );
        return TRUE;
 #endif
-      
+
       case WM_CREATE:
       {
           RECT rect;
@@ -1332,12 +1331,6 @@ static LRESULT MDIClientWndProc_common( HWND hwnd, UINT message,
 #ifndef __REACTOS__
           WND *wndPtr = WIN_GetPtr( hwnd );
 #endif
-       ci = HeapAlloc(GetProcessHeap(), 0, sizeof(MDICLIENTINFO));
-       if (NULL == ci)
-       {
-           return -1;
-       }
-       SetWindowLongPtr(hwnd, 0, (LONG_PTR) ci);
 
        /* Translation layer doesn't know what's in the cs->lpCreateParams
         * so we have to keep track of what environment we're in. */
@@ -1633,13 +1626,14 @@ LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
                     if( !ci->hwndChildMaximized ) break;
                     switch( id )
                     {
+                    case SC_CLOSE:
+                        if (!is_close_enabled(ci->hwndActiveChild, 0)) break;
                     case SC_SIZE:
                     case SC_MOVE:
                     case SC_MINIMIZE:
                     case SC_MAXIMIZE:
                     case SC_NEXTWINDOW:
                     case SC_PREVWINDOW:
-                    case SC_CLOSE:
                     case SC_RESTORE:
                         return SendMessageW( ci->hwndChildMaximized, WM_SYSCOMMAND,
                                              wParam, lParam);
@@ -1780,10 +1774,10 @@ LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
     case WM_SETFOCUS:
     case WM_CHILDACTIVATE:
     case WM_SYSCOMMAND:
-/* FIXME */
 #ifndef __REACTOS__
     case WM_SETVISIBLE:
 #endif
+    case WM_SHOWWINDOW:
     case WM_SIZE:
     case WM_NEXTMENU:
     case WM_SYSCHAR:
@@ -1861,13 +1855,13 @@ LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
         }
         break;
 
-/* FIXME */
 #ifndef __REACTOS__
     case WM_SETVISIBLE:
+#endif
+    case WM_SHOWWINDOW:
         if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
         else MDI_PostUpdate(client, ci, SB_BOTH+1);
         break;
-#endif
 
     case WM_SIZE:
         if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
@@ -2054,8 +2048,12 @@ BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
                 break;
             case VK_F4:
             case VK_RBUTTON:
-                wParam = SC_CLOSE;
-                break;
+                if (is_close_enabled(ci->hwndActiveChild, 0))
+                {
+                    wParam = SC_CLOSE;
+                    break;
+                }
+                /* fall through */
             default:
                 return 0;
             }
@@ -2077,8 +2075,16 @@ void WINAPI CalcChildScroll( HWND hwnd, INT scroll )
 #ifndef __REACTOS__
     HWND *list;
 #else
+    WINDOWINFO WindowInfo;
     HWND hWndCurrent;
 #endif
+    /* The rectangle returned by GetClientRect always has 0,0 as top left
+     * because it is in client coordinates. The rectangles returned by
+     * GetWindowRect are in screen coordinates to make this complicated.
+     *
+     * Apparently (in ReactOS at least) the rcClient returned by GetWindowInfo
+     * is in screen coordinates too.
+     */
 
     GetClientRect( hwnd, &clientRect );
     SetRectEmpty( &childRect );
@@ -2106,6 +2112,13 @@ void WINAPI CalcChildScroll( HWND hwnd, INT scroll )
         HeapFree( GetProcessHeap(), 0, list );
     }
 #else
+    WindowInfo.cbSize = sizeof(WindowInfo);
+    if (!GetWindowInfo(hwnd, &WindowInfo))
+    {
+       ERR("Can't get window info\n");
+       return;
+    }
+
     hWndCurrent = GetWindow(hwnd, GW_CHILD);
     while (hWndCurrent != NULL)
     {
@@ -2120,6 +2133,9 @@ void WINAPI CalcChildScroll( HWND hwnd, INT scroll )
             RECT WindowRect;
 
             GetWindowRect( hWndCurrent, &WindowRect );
+            OffsetRect(&WindowRect,
+                              -WindowInfo.rcClient.left,
+                              -WindowInfo.rcClient.top);
             UnionRect( &childRect, &WindowRect, &childRect );
         }
         hWndCurrent = GetWindow(hWndCurrent, GW_HWNDNEXT);
@@ -2129,24 +2145,31 @@ void WINAPI CalcChildScroll( HWND hwnd, INT scroll )
 
     /* set common info values */
     info.cbSize = sizeof(info);
-    info.fMask = SIF_POS | SIF_RANGE;
+    info.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
 
-    /* set the specific */
+    /* set the specific scrollbars*/
+    /* Note how we set nPos to 0 because we scroll the clients instead of
+     * the window, and we set nPage to 1 bigger than the clientRect because
+     * otherwise the scrollbar never disables. This causes a somewhat ugly
+     * effect though while scrolling.
+     */
     switch( scroll )
     {
        case SB_BOTH:
        case SB_HORZ:
                        info.nMin = childRect.left;
-                       info.nMax = childRect.right - clientRect.right;
-                       info.nPos = clientRect.left - childRect.left;
-                       SetScrollInfo(hwnd, scroll, &info, TRUE);
+                       info.nMax = childRect.right;
+                       info.nPos = 0;
+                       info.nPage = 1 + clientRect.right - clientRect.left;
+                       SetScrollInfo(hwnd, SB_HORZ, &info, TRUE);
                        if (scroll == SB_HORZ) break;
                        /* fall through */
        case SB_VERT:
                        info.nMin = childRect.top;
-                       info.nMax = childRect.bottom - clientRect.bottom;
-                       info.nPos = clientRect.top - childRect.top;
-                       SetScrollInfo(hwnd, scroll, &info, TRUE);
+                       info.nMax = childRect.bottom;
+                       info.nPos = 0;
+                       info.nPage = 1 + clientRect.bottom - clientRect.top;
+                       SetScrollInfo(hwnd, SB_VERT, &info, TRUE);
                        break;
     }
 }
@@ -2282,10 +2305,6 @@ static INT_PTR WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wPara
     {
        case WM_INITDIALOG:
        {
-#ifdef __REACTOS__
-           /* FIXME */
-           return FALSE;
-#else
            UINT widest       = 0;
            UINT length;
            UINT i;
@@ -2327,7 +2346,6 @@ static INT_PTR WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wPara
            /* Set the current selection */
            SendMessageW(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
            return TRUE;
-#endif
        }
 
        case WM_COMMAND:
@@ -2373,12 +2391,12 @@ static HWND MDI_MoreWindowsDialog(HWND hwnd)
     HRSRC hRes;
     HANDLE hDlgTmpl;
 
-    hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", (LPSTR)RT_DIALOG);
+    hRes = FindResourceA(User32Instance, "MDI_MOREWINDOWS", (LPSTR)RT_DIALOG);
 
     if (hRes == 0)
         return 0;
 
-    hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );
+    hDlgTmpl = LoadResource(User32Instance, hRes);
 
     if (hDlgTmpl == 0)
         return 0;
@@ -2388,7 +2406,7 @@ static HWND MDI_MoreWindowsDialog(HWND hwnd)
     if (template == 0)
         return 0;
 
-    return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
+    return (HWND) DialogBoxIndirectParamA(User32Instance,
                                           (LPDLGTEMPLATE) template,
                                           hwnd, MDI_MoreWindowsDlgProc, (LPARAM) hwnd);
 }
@@ -2405,8 +2423,6 @@ static HWND MDI_MoreWindowsDialog(HWND hwnd)
 
 static void MDI_SwapMenuItems(HWND parent, UINT pos1, UINT pos2)
 {
-/* FIXME */
-#ifndef __REACTOS__
     HWND *list;
     int i;
 
@@ -2418,5 +2434,4 @@ static void MDI_SwapMenuItems(HWND parent, UINT pos1, UINT pos2)
         else if (id == pos2) SetWindowLongW( list[i], GWL_ID, pos1 );
     }
     HeapFree( GetProcessHeap(), 0, list );
-#endif
 }