Replace GetModuleHandle("user32.dll") with User32Instance.
[reactos.git] / reactos / lib / user32 / windows / mdi.c
index 53e4ed1..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 ---------------------------- */
@@ -1086,20 +1122,20 @@ static BOOL MDI_AugmentFrameMenu( HWND frame, HWND hChild )
     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 );
-
-    AppendMenuA(menu,MF_HELP | MF_BITMAP,
-                   SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
+    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 );
 
     /* The system menu is replaced by the child icon */
     hIcon = (HICON)GetClassLongW(hChild, GCL_HICONSM);
     if (!hIcon)
         hIcon = (HICON)GetClassLongW(hChild, GCL_HICON);
     if (!hIcon)
-        hIcon = LoadImageW(0, MAKEINTRESOURCEW(IDI_WINLOGO), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
+        hIcon = LoadIconW(NULL, IDI_APPLICATION);
     if (hIcon)
     {
       HDC hMemDC;
@@ -1285,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;
@@ -1590,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);
@@ -1737,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:
@@ -1818,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 )
@@ -2011,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;
             }
@@ -2034,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 );
@@ -2063,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)
     {
@@ -2077,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);
@@ -2086,23 +2145,30 @@ 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;
+                       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;
+                       info.nMax = childRect.bottom;
+                       info.nPos = 0;
+                       info.nPage = 1 + clientRect.bottom - clientRect.top;
                        SetScrollInfo(hwnd, SB_VERT, &info, TRUE);
                        break;
     }
@@ -2239,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;
@@ -2284,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:
@@ -2330,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;
@@ -2345,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);
 }
@@ -2362,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;
 
@@ -2375,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
 }