mdi.c 69.3 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/* MDI.C
 *
 * Copyright 1994, Bob Amstadt
Alexandre Julliard's avatar
Alexandre Julliard committed
4
 *           1995,1996 Alex Korobka
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 *
6 7
 * This file contains routines to support MDI (Multiple Document
 * Interface) features .
Alexandre Julliard's avatar
Alexandre Julliard committed
8
 *
9 10 11 12 13 14 15 16 17 18 19 20 21 22
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
23
 * Notes: Fairly complete implementation.
Alexandre Julliard's avatar
Alexandre Julliard committed
24
 *        Also, Excel and WinWord do _not_ use MDI so if you're trying
25
 *	  to fix them look elsewhere.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
 *
 * Notes on how the "More Windows..." is implemented:
 *
 *      When we have more than 9 opened windows, a "More Windows..."
 *      option appears in the "Windows" menu. Each child window has
 *      a WND* associated with it, accesible via the children list of
 *      the parent window. This WND* has a wIDmenu member, which reflects
 *      the position of the child in the window list. For example, with
 *      9 child windows, we could have the following pattern:
 *
 *
 *
 *                Name of the child window    pWndChild->wIDmenu
 *                     Doc1                       5000
 *                     Doc2                       5001
 *                     Doc3                       5002
 *                     Doc4                       5003
 *                     Doc5                       5004
 *                     Doc6                       5005
 *                     Doc7                       5006
 *                     Doc8                       5007
 *                     Doc9                       5008
 *
 *
 *       The "Windows" menu, as the "More windows..." dialog, are constructed
 *       in this order. If we add a child, we would have the following list:
 *
 *
 *               Name of the child window    pWndChild->wIDmenu
 *                     Doc1                       5000
 *                     Doc2                       5001
 *                     Doc3                       5002
 *                     Doc4                       5003
 *                     Doc5                       5004
 *                     Doc6                       5005
 *                     Doc7                       5006
 *                     Doc8                       5007
 *                     Doc9                       5008
 *                     Doc10                      5009
 *
 *       But only 5000 to 5008 would be displayed in the "Windows" menu. We want
 *       the last created child to be in the menu, so we swap the last child with
 *       the 9th... Doc9 will be accessible via the "More Windows..." option.
 *
 *                     Doc1                       5000
 *                     Doc2                       5001
 *                     Doc3                       5002
 *                     Doc4                       5003
 *                     Doc5                       5004
 *                     Doc6                       5005
 *                     Doc7                       5006
 *                     Doc8                       5007
 *                     Doc9                       5009
 *                     Doc10                      5008
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
81
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
82

Alexandre Julliard's avatar
Alexandre Julliard committed
83
#include <stdlib.h>
84
#include <stdio.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
85
#include <string.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
86
#include <math.h>
87

88
#include "windef.h"
89
#include "winbase.h"
90
#include "wingdi.h"
91
#include "winuser.h"
92
#include "wownt32.h"
93
#include "wine/unicode.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
94
#include "win.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
95
#include "nonclient.h"
96
#include "controls.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
97
#include "user.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
98
#include "struct32.h"
99
#include "wine/debug.h"
100
#include "dlgs.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
101

102
WINE_DEFAULT_DEBUG_CHANNEL(mdi);
103

104 105 106 107 108 109 110 111 112 113
#define MDI_MAXLISTLENGTH       0x40
#define MDI_MAXTITLELENGTH      0xa1

#define MDI_NOFRAMEREPAINT      0
#define MDI_REPAINTFRAMENOW     1
#define MDI_REPAINTFRAME        2

#define WM_MDICALCCHILDSCROLL   0x10ac /* this is exactly what Windows uses */

/* "More Windows..." definitions */
114
#define MDI_MOREWINDOWSLIMIT    9       /* after this number of windows, a "More Windows..."
115 116
                                           option will appear under the Windows menu */
#define MDI_IDC_LISTBOX         100
117
#define IDS_MDI_MOREWINDOWS     13
118

Alexandre Julliard's avatar
Alexandre Julliard committed
119 120
#define MDIF_NEEDUPDATE		0x0001

121 122 123 124 125 126 127 128 129 130 131 132 133
typedef struct
{
    UINT      nActiveChildren;
    HWND      hwndChildMaximized;
    HWND      hwndActiveChild;
    HMENU     hWindowMenu;
    UINT      idFirstChild;
    LPWSTR    frameTitle;
    UINT      nTotalCreated;
    UINT      mdiFlags;
    UINT      sbRecalc;   /* SB_xxx flags for scrollbar fixup */
} MDICLIENTINFO;

134
static HBITMAP hBmpClose   = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
135

Alexandre Julliard's avatar
Alexandre Julliard committed
136
/* ----------------- declarations ----------------- */
137 138 139 140
static void MDI_UpdateFrameText( HWND, HWND, BOOL, LPCWSTR);
static BOOL MDI_AugmentFrameMenu( HWND, HWND );
static BOOL MDI_RestoreFrameMenu( HWND, HWND );
static LONG MDI_ChildActivate( HWND, HWND );
Alexandre Julliard's avatar
Alexandre Julliard committed
141

142 143
static HWND MDI_MoreWindowsDialog(HWND);
static void MDI_SwapMenuItems(HWND, UINT, UINT);
144
static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
145 146
static LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );

Alexandre Julliard's avatar
Alexandre Julliard committed
147 148 149
/* -------- Miscellaneous service functions ----------
 *
 *			MDI_GetChildByID
Alexandre Julliard's avatar
Alexandre Julliard committed
150
 */
151
static HWND MDI_GetChildByID(HWND hwnd, UINT id)
Alexandre Julliard's avatar
Alexandre Julliard committed
152
{
153 154 155 156
    HWND ret;
    HWND *win_array;
    int i;

157
    if (!(win_array = WIN_ListChildren( hwnd ))) return 0;
158 159 160 161 162
    for (i = 0; win_array[i]; i++)
    {
        if (GetWindowLongA( win_array[i], GWL_ID ) == id) break;
    }
    ret = win_array[i];
163
    HeapFree( GetProcessHeap(), 0, win_array );
164
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
165 166
}

167
static void MDI_PostUpdate(HWND hwnd, MDICLIENTINFO* ci, WORD recalc)
Alexandre Julliard's avatar
Alexandre Julliard committed
168
{
Alexandre Julliard's avatar
Alexandre Julliard committed
169 170 171
    if( !(ci->mdiFlags & MDIF_NEEDUPDATE) )
    {
	ci->mdiFlags |= MDIF_NEEDUPDATE;
172
	PostMessageA( hwnd, WM_MDICALCCHILDSCROLL, 0, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
173 174
    }
    ci->sbRecalc = recalc;
Alexandre Julliard's avatar
Alexandre Julliard committed
175 176
}

177 178 179 180 181 182 183 184 185

/*********************************************************************
 * MDIClient class descriptor
 */
const struct builtin_class_descr MDICLIENT_builtin_class =
{
    "MDIClient",            /* name */
    CS_GLOBALCLASS,         /* style */
    MDIClientWndProcA,      /* procA */
186
    MDIClientWndProcW,      /* procW */
187 188
    sizeof(MDICLIENTINFO),  /* extra */
    IDC_ARROWA,             /* cursor */
189
    (HBRUSH)(COLOR_APPWORKSPACE+1)    /* brush */
190 191 192
};


193 194 195
static MDICLIENTINFO *get_client_info( HWND client )
{
    MDICLIENTINFO *ret = NULL;
196
    WND *win = WIN_GetPtr( client );
197 198
    if (win)
    {
199 200
        if (win == WND_OTHER_PROCESS)
        {
201
            ERR( "client %p belongs to other process\n", client );
202 203
            return NULL;
        }
204
        if (win->cbWndExtra < sizeof(MDICLIENTINFO)) WARN( "%p is not an MDI client\n", client );
205
        else ret = (MDICLIENTINFO *)win->wExtra;
206
        WIN_ReleasePtr( win );
207 208 209 210
    }
    return ret;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
211 212 213
/**********************************************************************
 *			MDI_MenuModifyItem
 */
214
static void MDI_MenuModifyItem( HWND client, HWND hWndChild )
Alexandre Julliard's avatar
Alexandre Julliard committed
215
{
216 217 218
    MDICLIENTINFO *clientInfo = get_client_info( client );
    WCHAR buffer[128];
    UINT n, id;
Alexandre Julliard's avatar
Alexandre Julliard committed
219

220
    if (!clientInfo || !clientInfo->hWindowMenu) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
221

222
    id = GetWindowLongA( hWndChild, GWL_ID );
223 224 225 226 227 228 229 230
    if (id >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT) return;
    buffer[0] = '&';
    buffer[1] = '1' + id - clientInfo->idFirstChild;
    buffer[2] = ' ';
    GetWindowTextW( hWndChild, buffer + 3, sizeof(buffer)/sizeof(WCHAR) - 3 );

    n = GetMenuState(clientInfo->hWindowMenu, id, MF_BYCOMMAND);
    ModifyMenuW(clientInfo->hWindowMenu, id, MF_BYCOMMAND | MF_STRING, id, buffer );
231
    CheckMenuItem(clientInfo->hWindowMenu, id, n & MF_CHECKED);
Alexandre Julliard's avatar
Alexandre Julliard committed
232 233 234 235 236
}

/**********************************************************************
 *			MDI_MenuDeleteItem
 */
237
static BOOL MDI_MenuDeleteItem( HWND client, HWND hWndChild )
Alexandre Julliard's avatar
Alexandre Julliard committed
238
{
239 240
    WCHAR    	 buffer[128];
    static const WCHAR format[] = {'&','%','d',' ',0};
241
    MDICLIENTINFO *clientInfo = get_client_info( client );
242
    UINT	 index      = 0,id,n;
Alexandre Julliard's avatar
Alexandre Julliard committed
243

244 245
    if( !clientInfo->nActiveChildren || !clientInfo->hWindowMenu )
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
246

247
    id = GetWindowLongA( hWndChild, GWL_ID );
248
    DeleteMenu(clientInfo->hWindowMenu,id,MF_BYCOMMAND);
Alexandre Julliard's avatar
Alexandre Julliard committed
249

250
 /* walk the rest of MDI children to prevent gaps in the id
Alexandre Julliard's avatar
Alexandre Julliard committed
251
  * sequence and in the menu child list */
Alexandre Julliard's avatar
Alexandre Julliard committed
252

253
    for( index = id+1; index <= clientInfo->nActiveChildren +
Alexandre Julliard's avatar
Alexandre Julliard committed
254
				clientInfo->idFirstChild; index++ )
Alexandre Julliard's avatar
Alexandre Julliard committed
255
    {
256 257 258 259 260 261 262
        HWND hwnd = MDI_GetChildByID(client,index);
        if (!hwnd)
        {
            TRACE("no window for id=%i\n",index);
            continue;
        }

Alexandre Julliard's avatar
Alexandre Julliard committed
263
	/* set correct id */
264
        SetWindowLongW( hwnd, GWL_ID, GetWindowLongW( hwnd, GWL_ID ) - 1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
265

266
	n = wsprintfW(buffer, format ,index - clientInfo->idFirstChild);
267
        GetWindowTextW( hwnd, buffer + n, sizeof(buffer)/sizeof(WCHAR) - n );
Alexandre Julliard's avatar
Alexandre Julliard committed
268

269
	/*  change menu if the current child is to be shown in the
270 271
         *  "Windows" menu
         */
272
        if (index <= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
273
	ModifyMenuW(clientInfo->hWindowMenu ,index ,MF_BYCOMMAND | MF_STRING,
274
                      index - 1 , buffer );
Alexandre Julliard's avatar
Alexandre Julliard committed
275
    }
276

277
    /*  We must restore the "More Windows..." option if there are enough children
278 279 280
     */
    if (clientInfo->nActiveChildren - 1 > MDI_MOREWINDOWSLIMIT)
    {
281
        WCHAR szTmp[50];
282
        LoadStringW(GetModuleHandleA("USER32"), IDS_MDI_MOREWINDOWS, szTmp, sizeof(szTmp)/sizeof(szTmp[0]));
283
        AppendMenuW(clientInfo->hWindowMenu, MF_STRING, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT, szTmp);
284
    }
285
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
286 287 288 289 290
}

/**********************************************************************
 * 			MDI_GetWindow
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
291
 * returns "activateable" child different from the current or zero
Alexandre Julliard's avatar
Alexandre Julliard committed
292
 */
293
static HWND MDI_GetWindow(MDICLIENTINFO *clientInfo, HWND hWnd, BOOL bNext,
Alexandre Julliard's avatar
Alexandre Julliard committed
294
                            DWORD dwStyleMask )
Alexandre Julliard's avatar
Alexandre Julliard committed
295
{
296 297 298 299
    int i;
    HWND *list;
    HWND last = 0;

Alexandre Julliard's avatar
Alexandre Julliard committed
300
    dwStyleMask |= WS_DISABLED | WS_VISIBLE;
Alexandre Julliard's avatar
Alexandre Julliard committed
301
    if( !hWnd ) hWnd = clientInfo->hwndActiveChild;
Alexandre Julliard's avatar
Alexandre Julliard committed
302

303
    if (!(list = WIN_ListChildren( GetParent(hWnd) ))) return 0;
304 305 306 307
    i = 0;
    /* start from next after hWnd */
    while (list[i] && list[i] != hWnd) i++;
    if (list[i]) i++;
Alexandre Julliard's avatar
Alexandre Julliard committed
308

309
    for ( ; list[i]; i++)
Alexandre Julliard's avatar
Alexandre Julliard committed
310
    {
311 312 313 314 315 316 317 318 319 320 321 322
        if (GetWindow( list[i], GW_OWNER )) continue;
        if ((GetWindowLongW( list[i], GWL_STYLE ) & dwStyleMask) != WS_VISIBLE) continue;
        last = list[i];
        if (bNext) goto found;
    }
    /* now restart from the beginning */
    for (i = 0; list[i] && list[i] != hWnd; i++)
    {
        if (GetWindow( list[i], GW_OWNER )) continue;
        if ((GetWindowLongW( list[i], GWL_STYLE ) & dwStyleMask) != WS_VISIBLE) continue;
        last = list[i];
        if (bNext) goto found;
Alexandre Julliard's avatar
Alexandre Julliard committed
323
    }
324
 found:
325
    HeapFree( GetProcessHeap(), 0, list );
326
    return last;
Alexandre Julliard's avatar
Alexandre Julliard committed
327 328
}

Alexandre Julliard's avatar
Alexandre Julliard committed
329 330 331
/**********************************************************************
 *			MDI_CalcDefaultChildPos
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
332
 *  It seems that the default height is about 2/3 of the client rect
Alexandre Julliard's avatar
Alexandre Julliard committed
333
 */
334
static void MDI_CalcDefaultChildPos( HWND hwnd, WORD n, LPPOINT lpPos, INT delta)
Alexandre Julliard's avatar
Alexandre Julliard committed
335
{
336
    INT  nstagger;
337
    RECT rect;
338
    INT  spacing = GetSystemMetrics(SM_CYCAPTION) +
339
		     GetSystemMetrics(SM_CYFRAME) - 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
340

341
    GetClientRect( hwnd, &rect );
342
    if( rect.bottom - rect.top - delta >= spacing )
Alexandre Julliard's avatar
Alexandre Julliard committed
343 344 345 346 347 348
	rect.bottom -= delta;

    nstagger = (rect.bottom - rect.top)/(3 * spacing);
    lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
    lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
    lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
Alexandre Julliard's avatar
Alexandre Julliard committed
349
}
Alexandre Julliard's avatar
Alexandre Julliard committed
350

Alexandre Julliard's avatar
Alexandre Julliard committed
351
/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
352
 *            MDISetMenu
Alexandre Julliard's avatar
Alexandre Julliard committed
353
 */
354 355
static LRESULT MDISetMenu( HWND hwnd, HMENU hmenuFrame,
                           HMENU hmenuWindow)
Alexandre Julliard's avatar
Alexandre Julliard committed
356
{
Alexandre Julliard's avatar
Alexandre Julliard committed
357
    MDICLIENTINFO *ci;
358 359
    HWND hwndFrame = GetParent(hwnd);
    HMENU oldFrameMenu = GetMenu(hwndFrame);
Alexandre Julliard's avatar
Alexandre Julliard committed
360

361
    TRACE("%p %p %p\n", hwnd, hmenuFrame, hmenuWindow);
Alexandre Julliard's avatar
Alexandre Julliard committed
362

363 364 365 366 367
    if (hmenuFrame && !IsMenu(hmenuFrame))
    {
	WARN("hmenuFrame is not a menu handle\n");
	return 0L;
    }
368

369 370 371 372 373
    if (hmenuWindow && !IsMenu(hmenuWindow))
    {
	WARN("hmenuWindow is not a menu handle\n");
	return 0L;
    }
374 375

    if (!(ci = get_client_info( hwnd ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
376

Alexandre Julliard's avatar
Alexandre Julliard committed
377
    if( ci->hwndChildMaximized && hmenuFrame && hmenuFrame!=oldFrameMenu )
378
        MDI_RestoreFrameMenu( GetParent(hwnd), ci->hwndChildMaximized );
Alexandre Julliard's avatar
Alexandre Julliard committed
379

380
    if( hmenuWindow && ci->hWindowMenu && hmenuWindow!=ci->hWindowMenu )
Alexandre Julliard's avatar
Alexandre Julliard committed
381
    {
382
        /* delete menu items from ci->hWindowMenu
Alexandre Julliard's avatar
Alexandre Julliard committed
383
         * and add them to hmenuWindow */
Alexandre Julliard's avatar
Alexandre Julliard committed
384

385 386
        INT i = GetMenuItemCount(ci->hWindowMenu) - 1;
        INT pos = GetMenuItemCount(hmenuWindow) + 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
387

388
        AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
389

Alexandre Julliard's avatar
Alexandre Julliard committed
390 391
        if( ci->nActiveChildren )
        {
392
            INT j;
393 394
            LPWSTR buffer = NULL;
	    MENUITEMINFOW mii;
395 396 397 398 399 400 401 402
            INT nbWindowsMenuItems; /* num of documents shown + "More Windows..." if present */

            if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
                nbWindowsMenuItems = ci->nActiveChildren;
            else
                nbWindowsMenuItems = MDI_MOREWINDOWSLIMIT + 1;

            j = i - nbWindowsMenuItems + 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
403

Alexandre Julliard's avatar
Alexandre Julliard committed
404 405
            for( ; i >= j ; i-- )
            {
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
		memset(&mii, 0, sizeof(mii));
		mii.cbSize = sizeof(mii);
		mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE
		  | MIIM_SUBMENU | MIIM_TYPE | MIIM_BITMAP;

		GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
		if(mii.cch) { /* Menu is MFT_STRING */
		    mii.cch++; /* add room for '\0' */
		    buffer = HeapAlloc(GetProcessHeap(), 0,
				       mii.cch * sizeof(WCHAR));
		    mii.dwTypeData = buffer;
		    GetMenuItemInfoW(ci->hWindowMenu, i, TRUE, &mii);
		}
                DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
                InsertMenuItemW(hmenuWindow, pos, TRUE, &mii);
		if(buffer) {
		    HeapFree(GetProcessHeap(), 0, buffer);
		    buffer = NULL;
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
425 426
            }
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
427

Alexandre Julliard's avatar
Alexandre Julliard committed
428
        /* remove separator */
429
        DeleteMenu(ci->hWindowMenu, i, MF_BYPOSITION);
Alexandre Julliard's avatar
Alexandre Julliard committed
430

Alexandre Julliard's avatar
Alexandre Julliard committed
431
        ci->hWindowMenu = hmenuWindow;
432
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
433

434
    if (hmenuFrame)
Alexandre Julliard's avatar
Alexandre Julliard committed
435
    {
436
        SetMenu(hwndFrame, hmenuFrame);
437 438 439
        if( hmenuFrame!=oldFrameMenu )
        {
            if( ci->hwndChildMaximized )
440
                MDI_AugmentFrameMenu( GetParent(hwnd), ci->hwndChildMaximized );
441
            return (LRESULT)oldFrameMenu;
442
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
443
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
444 445
    else
    {
446 447 448
        HMENU menu = GetMenu( GetParent(hwnd) );
	INT nItems = GetMenuItemCount(menu) - 1;
	UINT iId = GetMenuItemID(menu,nItems) ;
Alexandre Julliard's avatar
Alexandre Julliard committed
449 450 451 452 453 454 455 456 457 458

	if( !(iId == SC_RESTORE || iId == SC_CLOSE) )
	{
	    /* SetMenu() may already have been called, meaning that this window
	     * already has its menu. But they may have done a SetMenu() on
	     * an MDI window, and called MDISetMenu() after the fact, meaning
	     * that the "if" to this "else" wouldn't catch the need to
	     * augment the frame menu.
	     */
	    if( ci->hwndChildMaximized )
459
		MDI_AugmentFrameMenu( GetParent(hwnd), ci->hwndChildMaximized );
Alexandre Julliard's avatar
Alexandre Julliard committed
460 461
	}
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
462 463
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
464

Alexandre Julliard's avatar
Alexandre Julliard committed
465 466 467
/**********************************************************************
 *            MDIRefreshMenu
 */
468 469
static LRESULT MDIRefreshMenu( HWND hwnd, HMENU hmenuFrame,
                           HMENU hmenuWindow)
Alexandre Julliard's avatar
Alexandre Julliard committed
470
{
471 472
    HWND hwndFrame = GetParent(hwnd);
    HMENU oldFrameMenu = GetMenu(hwndFrame);
Alexandre Julliard's avatar
Alexandre Julliard committed
473

474
    TRACE("%p %p %p\n", hwnd, hmenuFrame, hmenuWindow);
Alexandre Julliard's avatar
Alexandre Julliard committed
475

476
    FIXME("partially function stub\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
477

478
    return (LRESULT)oldFrameMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
479 480
}

Alexandre Julliard's avatar
Alexandre Julliard committed
481 482 483 484

/* ------------------ MDI child window functions ---------------------- */


Alexandre Julliard's avatar
Alexandre Julliard committed
485
/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
486
 *					MDICreateChild
Alexandre Julliard's avatar
Alexandre Julliard committed
487
 */
488
static HWND MDICreateChild( HWND parent, MDICLIENTINFO *ci,
489
			    LPMDICREATESTRUCTA cs, BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
490
{
491
    POINT          pos[2];
Alexandre Julliard's avatar
Alexandre Julliard committed
492
    DWORD	     style = cs->style | (WS_CHILD | WS_CLIPSIBLINGS);
493
    HWND 	     hwnd, hwndMax = 0;
494 495
    UINT wIDmenu = ci->idFirstChild + ci->nActiveChildren;
    WND *wndParent;
496
    static const WCHAR lpstrDef[] = {'j','u','n','k','!',0};
Alexandre Julliard's avatar
Alexandre Julliard committed
497

498
    TRACE("origin %i,%i - dim %i,%i, style %08lx\n",
499
                cs->x, cs->y, cs->cx, cs->cy, cs->style);
Alexandre Julliard's avatar
Alexandre Julliard committed
500
    /* calculate placement */
501
    MDI_CalcDefaultChildPos(parent, ci->nTotalCreated++, pos, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
502

503 504
    if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16 || !cs->cx) cs->cx = pos[1].x;
    if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16 || !cs->cy) cs->cy = pos[1].y;
Alexandre Julliard's avatar
Alexandre Julliard committed
505

506
    if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
Alexandre Julliard's avatar
Alexandre Julliard committed
507
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
508 509
 	cs->x = pos[0].x;
	cs->y = pos[0].y;
Alexandre Julliard's avatar
Alexandre Julliard committed
510
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
511 512

    /* restore current maximized child */
513
    if( (style & WS_VISIBLE) && ci->hwndChildMaximized )
Alexandre Julliard's avatar
Alexandre Julliard committed
514
    {
515
	TRACE("Restoring current maximized child %p\n", ci->hwndChildMaximized);
Alexandre Julliard's avatar
Alexandre Julliard committed
516
	if( style & WS_MAXIMIZE )
517
	    SendMessageW(parent, WM_SETREDRAW, FALSE, 0L);
Alexandre Julliard's avatar
Alexandre Julliard committed
518
	hwndMax = ci->hwndChildMaximized;
519
	ShowWindow( hwndMax, SW_SHOWNOACTIVATE );
Alexandre Julliard's avatar
Alexandre Julliard committed
520
	if( style & WS_MAXIMIZE )
521
	    SendMessageW(parent, WM_SETREDRAW, TRUE, 0L);
Alexandre Julliard's avatar
Alexandre Julliard committed
522
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
523

524
    if (ci->nActiveChildren <= MDI_MOREWINDOWSLIMIT)
Alexandre Julliard's avatar
Alexandre Julliard committed
525
    /* this menu is needed to set a check mark in MDI_ChildActivate */
526
    if (ci->hWindowMenu != 0)
527
        AppendMenuW(ci->hWindowMenu, MF_STRING, wIDmenu, lpstrDef);
Alexandre Julliard's avatar
Alexandre Julliard committed
528

Alexandre Julliard's avatar
Alexandre Julliard committed
529
    ci->nActiveChildren++;
Alexandre Julliard's avatar
Alexandre Julliard committed
530 531

    /* fix window style */
532
    wndParent = WIN_FindWndPtr( parent );
533
    if( !(wndParent->dwStyle & MDIS_ALLCHILDSTYLES) )
Alexandre Julliard's avatar
Alexandre Julliard committed
534
    {
535
	TRACE("MDIS_ALLCHILDSTYLES is missing, fixing window style\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
536 537 538
        style &= (WS_CHILD | WS_CLIPSIBLINGS | WS_MINIMIZE | WS_MAXIMIZE |
                  WS_CLIPCHILDREN | WS_DISABLED | WS_VSCROLL | WS_HSCROLL );
        style |= (WS_VISIBLE | WS_OVERLAPPEDWINDOW);
Alexandre Julliard's avatar
Alexandre Julliard committed
539
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
540

541
    if( wndParent->flags & WIN_ISWIN32 )
Alexandre Julliard's avatar
Alexandre Julliard committed
542
    {
543
        WIN_ReleaseWndPtr( wndParent );
544 545 546
	if(unicode)
	{
	    MDICREATESTRUCTW *csW = (MDICREATESTRUCTW *)cs;
547
	    hwnd = CreateWindowW( csW->szClass, csW->szTitle, style,
548
                                csW->x, csW->y, csW->cx, csW->cy, parent,
549 550 551
                                (HMENU)wIDmenu, csW->hOwner, csW );
	}
	else
552
	    hwnd = CreateWindowA( cs->szClass, cs->szTitle, style,
553
                                cs->x, cs->y, cs->cx, cs->cy, parent,
554
                                (HMENU)wIDmenu, cs->hOwner, cs );
Alexandre Julliard's avatar
Alexandre Julliard committed
555 556
    }
    else
Alexandre Julliard's avatar
Alexandre Julliard committed
557
    {
558 559
        MDICREATESTRUCT16 cs16;
        SEGPTR title, cls, seg_cs16;
Alexandre Julliard's avatar
Alexandre Julliard committed
560

561
        WIN_ReleaseWndPtr( wndParent );
562 563 564 565
        STRUCT32_MDICREATESTRUCT32Ato16( cs, &cs16 );
        cs16.szTitle = title = MapLS( cs->szTitle );
        cs16.szClass = cls = MapLS( cs->szClass );
        seg_cs16 = MapLS( &cs16 );
566
        hwnd = WIN_Handle32( CreateWindow16( cs->szClass, cs->szTitle, style,
567
                                             cs16.x, cs16.y, cs16.cx, cs16.cy,
568
                                             HWND_16(parent), (HMENU16)wIDmenu,
569 570 571 572
                                             cs16.hOwner, (LPVOID)seg_cs16 ));
        UnMapLS( seg_cs16 );
        UnMapLS( title );
        UnMapLS( cls );
Alexandre Julliard's avatar
Alexandre Julliard committed
573
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
574

Alexandre Julliard's avatar
Alexandre Julliard committed
575 576
    /* MDI windows are WS_CHILD so they won't be activated by CreateWindow */

Alexandre Julliard's avatar
Alexandre Julliard committed
577 578
    if (hwnd)
    {
579
	/* All MDI child windows have the WS_EX_MDICHILD style */
580
        SetWindowLongW( hwnd, GWL_EXSTYLE, GetWindowLongW( hwnd, GWL_EXSTYLE ) | WS_EX_MDICHILD );
581

582 583 584 585
        /*  If we have more than 9 windows, we must insert the new one at the
         *  9th position in order to see it in the "Windows" menu
         */
        if (ci->nActiveChildren > MDI_MOREWINDOWSLIMIT)
586 587
            MDI_SwapMenuItems( parent, GetWindowLongW( hwnd, GWL_ID ),
                               ci->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
588

589
	MDI_MenuModifyItem(parent, hwnd);
590

591 592
        /* Have we hit the "More Windows..." limit? If so, we must
         * add a "More Windows..." option
593 594 595
         */
        if (ci->nActiveChildren == MDI_MOREWINDOWSLIMIT + 1)
        {
596
            WCHAR szTmp[50];
597
            LoadStringW(GetModuleHandleA("USER32"), IDS_MDI_MOREWINDOWS, szTmp, sizeof(szTmp)/sizeof(szTmp[0]));
598

599
            ModifyMenuW(ci->hWindowMenu,
600 601 602
                        ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
                        MF_BYCOMMAND | MF_STRING,
                        ci->idFirstChild + MDI_MOREWINDOWSLIMIT,
603 604
                        szTmp);
        }
605 606

        if( IsIconic(hwnd) && ci->hwndActiveChild )
607
	{
608
	    TRACE("Minimizing created MDI child %p\n", hwnd);
609
	    ShowWindow( hwnd, SW_SHOWMINNOACTIVE );
610
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
611
	else
Alexandre Julliard's avatar
Alexandre Julliard committed
612
	{
613 614
            /* WS_VISIBLE is clear if a) the MDI client has
             * MDIS_ALLCHILDSTYLES style and 2) the flag is cleared in the
615
             * MDICreateStruct. If so the created window is not shown nor
616 617
             * activated.
             */
618
            if (IsWindowVisible(hwnd)) ShowWindow(hwnd, SW_SHOW);
Alexandre Julliard's avatar
Alexandre Julliard committed
619
	}
620
        TRACE("created child - %p\n",hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
621
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
622
    else
Alexandre Julliard's avatar
Alexandre Julliard committed
623
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
624
	ci->nActiveChildren--;
625 626 627
	DeleteMenu(ci->hWindowMenu,wIDmenu,MF_BYCOMMAND);
	if( IsWindow(hwndMax) )
	    ShowWindow(hwndMax, SW_SHOWMAXIMIZED);
Alexandre Julliard's avatar
Alexandre Julliard committed
628
    }
629

Alexandre Julliard's avatar
Alexandre Julliard committed
630 631 632
    return hwnd;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
633 634
/**********************************************************************
 *			MDI_ChildGetMinMaxInfo
Alexandre Julliard's avatar
Alexandre Julliard committed
635
 *
636
 * Note: The rule here is that client rect of the maximized MDI child
Alexandre Julliard's avatar
Alexandre Julliard committed
637
 *	 is equal to the client rect of the MDI client window.
Alexandre Julliard's avatar
Alexandre Julliard committed
638
 */
639
static void MDI_ChildGetMinMaxInfo( HWND client, HWND hwnd, MINMAXINFO* lpMinMax )
Alexandre Julliard's avatar
Alexandre Julliard committed
640
{
641
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
642

643 644 645
    GetClientRect( client, &rect );
    AdjustWindowRectEx( &rect, GetWindowLongW( hwnd, GWL_STYLE ),
                        0, GetWindowLongW( hwnd, GWL_EXSTYLE ));
Alexandre Julliard's avatar
Alexandre Julliard committed
646

Alexandre Julliard's avatar
Alexandre Julliard committed
647 648
    lpMinMax->ptMaxSize.x = rect.right -= rect.left;
    lpMinMax->ptMaxSize.y = rect.bottom -= rect.top;
Alexandre Julliard's avatar
Alexandre Julliard committed
649

Alexandre Julliard's avatar
Alexandre Julliard committed
650
    lpMinMax->ptMaxPosition.x = rect.left;
651
    lpMinMax->ptMaxPosition.y = rect.top;
Alexandre Julliard's avatar
Alexandre Julliard committed
652

653
    TRACE("max rect (%ld,%ld - %ld, %ld)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
654
                        rect.left,rect.top,rect.right,rect.bottom);
Alexandre Julliard's avatar
Alexandre Julliard committed
655 656
}

Alexandre Julliard's avatar
Alexandre Julliard committed
657
/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
658
 *			MDI_SwitchActiveChild
659
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
660
 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
661
 *       being activated
Alexandre Julliard's avatar
Alexandre Julliard committed
662
 */
663 664
static void MDI_SwitchActiveChild( HWND clientHwnd, HWND childHwnd,
                                   BOOL bNextWindow )
Alexandre Julliard's avatar
Alexandre Julliard committed
665
{
666 667
    HWND	   hwndTo    = 0;
    HWND	   hwndPrev  = 0;
668
    MDICLIENTINFO *ci = get_client_info( clientHwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
669

670
    hwndTo = MDI_GetWindow(ci, childHwnd, bNextWindow, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
671

672
    TRACE("from %p, to %p\n",childHwnd,hwndTo);
Alexandre Julliard's avatar
Alexandre Julliard committed
673

674
    if ( !hwndTo ) return; /* no window to switch to */
Alexandre Julliard's avatar
Alexandre Julliard committed
675

Alexandre Julliard's avatar
Alexandre Julliard committed
676
    hwndPrev = ci->hwndActiveChild;
Alexandre Julliard's avatar
Alexandre Julliard committed
677

Alexandre Julliard's avatar
Alexandre Julliard committed
678
    if ( hwndTo != hwndPrev )
Alexandre Julliard's avatar
Alexandre Julliard committed
679
    {
680
	SetWindowPos( hwndTo, HWND_TOP, 0, 0, 0, 0,
681
                      SWP_NOMOVE | SWP_NOSIZE );
Alexandre Julliard's avatar
Alexandre Julliard committed
682

Alexandre Julliard's avatar
Alexandre Julliard committed
683
	if( bNextWindow && hwndPrev )
684
	    SetWindowPos( hwndPrev, HWND_BOTTOM, 0, 0, 0, 0,
685
                          SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
Alexandre Julliard's avatar
Alexandre Julliard committed
686
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
687
}
Alexandre Julliard's avatar
Alexandre Julliard committed
688

689

Alexandre Julliard's avatar
Alexandre Julliard committed
690 691 692
/**********************************************************************
 *                                      MDIDestroyChild
 */
693
static LRESULT MDIDestroyChild( HWND parent, MDICLIENTINFO *ci,
694
                                HWND child, BOOL flagDestroy )
Alexandre Julliard's avatar
Alexandre Julliard committed
695
{
696
    if( child == ci->hwndActiveChild )
Alexandre Julliard's avatar
Alexandre Julliard committed
697
    {
698 699
        MDI_SwitchActiveChild(parent, child, TRUE);

Alexandre Julliard's avatar
Alexandre Julliard committed
700
        if( child == ci->hwndActiveChild )
Alexandre Julliard's avatar
Alexandre Julliard committed
701
        {
702 703 704 705 706 707 708 709
            ShowWindow( child, SW_HIDE);
            if( child == ci->hwndChildMaximized )
            {
                HWND frame = GetParent(parent);
                MDI_RestoreFrameMenu( frame, child );
                ci->hwndChildMaximized = 0;
                MDI_UpdateFrameText( frame, parent, TRUE, NULL);
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
710

711
            MDI_ChildActivate(parent, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
712
        }
713
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
714

715
    MDI_MenuDeleteItem(parent, child);
716

717
    ci->nActiveChildren--;
Alexandre Julliard's avatar
Alexandre Julliard committed
718

719
    TRACE("child destroyed - %p\n",child);
Alexandre Julliard's avatar
Alexandre Julliard committed
720

721 722 723 724
    if (flagDestroy)
    {
        MDI_PostUpdate(GetParent(child), ci, SB_BOTH+1);
        DestroyWindow(child);
Alexandre Julliard's avatar
Alexandre Julliard committed
725
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
726
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
727 728
}

Alexandre Julliard's avatar
Alexandre Julliard committed
729

Alexandre Julliard's avatar
Alexandre Julliard committed
730
/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
731 732 733
 *					MDI_ChildActivate
 *
 * Note: hWndChild is NULL when last child is being destroyed
Alexandre Julliard's avatar
Alexandre Julliard committed
734
 */
735
static LONG MDI_ChildActivate( HWND client, HWND child )
Alexandre Julliard's avatar
Alexandre Julliard committed
736
{
737 738 739 740
    MDICLIENTINFO *clientInfo = get_client_info( client );
    HWND prevActiveWnd = clientInfo->hwndActiveChild;
    BOOL isActiveFrameWnd;

741
    if (child && (!IsWindowEnabled( child ))) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
742

743
    /* Don't activate if it is already active. Might happen
744
       since ShowWindow DOES activate MDI children */
745
    if (clientInfo->hwndActiveChild == child) return 0;
746

747
    TRACE("%p\n", child);
748 749

    isActiveFrameWnd = (GetActiveWindow() == GetParent(client));
Alexandre Julliard's avatar
Alexandre Julliard committed
750 751

    /* deactivate prev. active child */
752
    if(prevActiveWnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
753
    {
754 755
        SetWindowLongA( prevActiveWnd, GWL_STYLE,
                        GetWindowLongA( prevActiveWnd, GWL_STYLE ) | WS_SYSMENU );
756
	SendMessageA( prevActiveWnd, WM_NCACTIVATE, FALSE, 0L );
757
        SendMessageA( prevActiveWnd, WM_MDIACTIVATE, (WPARAM)prevActiveWnd, (LPARAM)child);
Alexandre Julliard's avatar
Alexandre Julliard committed
758 759
        /* uncheck menu item */
       	if( clientInfo->hWindowMenu )
760
        {
761
            UINT prevID = GetWindowLongA( prevActiveWnd, GWL_ID );
762

763 764
            if (prevID - clientInfo->idFirstChild < MDI_MOREWINDOWSLIMIT)
                CheckMenuItem( clientInfo->hWindowMenu, prevID, 0);
765 766 767
            else
       	        CheckMenuItem( clientInfo->hWindowMenu,
                               clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1, 0);
768
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
769
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
770 771

    /* set appearance */
772
    if (clientInfo->hwndChildMaximized && clientInfo->hwndChildMaximized != child)
773
    {
774 775 776 777 778 779
        if( child )
        {
            clientInfo->hwndActiveChild = child;
            ShowWindow( child, SW_SHOWMAXIMIZED);
        }
        else ShowWindow( clientInfo->hwndActiveChild, SW_SHOWNORMAL );
780
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
781

782
    clientInfo->hwndActiveChild = child;
Alexandre Julliard's avatar
Alexandre Julliard committed
783 784

    /* check if we have any children left */
785
    if( !child )
Alexandre Julliard's avatar
Alexandre Julliard committed
786 787
    {
	if( isActiveFrameWnd )
788 789
	    SetFocus( client );
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
790
    }
791

Alexandre Julliard's avatar
Alexandre Julliard committed
792 793
    /* check menu item */
    if( clientInfo->hWindowMenu )
794
    {
795 796 797 798
        UINT id = GetWindowLongA( child, GWL_ID );
        /* The window to be activated must be displayed in the "Windows" menu */
        if (id >= clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT)
        {
799 800 801
            MDI_SwapMenuItems( GetParent(child),
                               id, clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1);
            id = clientInfo->idFirstChild + MDI_MOREWINDOWSLIMIT - 1;
802 803
            MDI_MenuModifyItem( GetParent(child), child );
        }
804

805
        CheckMenuItem(clientInfo->hWindowMenu, id, MF_CHECKED);
806
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
807
    /* bring active child to the top */
808
    SetWindowPos( child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
Alexandre Julliard's avatar
Alexandre Julliard committed
809 810

    if( isActiveFrameWnd )
Alexandre Julliard's avatar
Alexandre Julliard committed
811
    {
812 813 814
	    SendMessageA( child, WM_NCACTIVATE, TRUE, 0L);
	    if( GetFocus() == client )
		SendMessageA( client, WM_SETFOCUS, (WPARAM)client, 0L );
Alexandre Julliard's avatar
Alexandre Julliard committed
815
	    else
816
		SetFocus( client );
Alexandre Julliard's avatar
Alexandre Julliard committed
817
    }
818 819
    SendMessageA( child, WM_MDIACTIVATE, (WPARAM)prevActiveWnd, (LPARAM)child );
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
820
}
Alexandre Julliard's avatar
Alexandre Julliard committed
821

Alexandre Julliard's avatar
Alexandre Julliard committed
822 823 824 825 826
/* -------------------- MDI client window functions ------------------- */

/**********************************************************************
 *				CreateMDIMenuBitmap
 */
827
static HBITMAP CreateMDIMenuBitmap(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
828
{
829 830
 HDC 		hDCSrc  = CreateCompatibleDC(0);
 HDC		hDCDest	= CreateCompatibleDC(hDCSrc);
831
 HBITMAP	hbClose = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_OLD_CLOSE) );
832 833
 HBITMAP	hbCopy;
 HBITMAP	hobjSrc, hobjDest;
Alexandre Julliard's avatar
Alexandre Julliard committed
834

835
 hobjSrc = SelectObject(hDCSrc, hbClose);
836
 hbCopy = CreateCompatibleBitmap(hDCSrc,GetSystemMetrics(SM_CXSIZE),GetSystemMetrics(SM_CYSIZE));
837
 hobjDest = SelectObject(hDCDest, hbCopy);
Alexandre Julliard's avatar
Alexandre Julliard committed
838

839 840
 BitBlt(hDCDest, 0, 0, GetSystemMetrics(SM_CXSIZE), GetSystemMetrics(SM_CYSIZE),
          hDCSrc, GetSystemMetrics(SM_CXSIZE), 0, SRCCOPY);
841

842 843 844
 SelectObject(hDCSrc, hobjSrc);
 DeleteObject(hbClose);
 DeleteDC(hDCSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
845

846
 hobjSrc = SelectObject( hDCDest, GetStockObject(BLACK_PEN) );
Alexandre Julliard's avatar
Alexandre Julliard committed
847

848 849
 MoveToEx( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, 0, NULL );
 LineTo( hDCDest, GetSystemMetrics(SM_CXSIZE) - 1, GetSystemMetrics(SM_CYSIZE) - 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
850

851 852 853
 SelectObject(hDCDest, hobjSrc );
 SelectObject(hDCDest, hobjDest);
 DeleteDC(hDCDest);
Alexandre Julliard's avatar
Alexandre Julliard committed
854 855 856 857

 return hbCopy;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
858
/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
859
 *				MDICascade
Alexandre Julliard's avatar
Alexandre Julliard committed
860
 */
861
static LONG MDICascade( HWND client, MDICLIENTINFO *ci )
Alexandre Julliard's avatar
Alexandre Julliard committed
862
{
863 864 865 866
    HWND *win_array;
    BOOL has_icons = FALSE;
    int i, total;

Alexandre Julliard's avatar
Alexandre Julliard committed
867
    if (ci->hwndChildMaximized)
868
        SendMessageA( client, WM_MDIRESTORE,
869
                        (WPARAM)ci->hwndChildMaximized, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
870

Alexandre Julliard's avatar
Alexandre Julliard committed
871
    if (ci->nActiveChildren == 0) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
872

873
    if (!(win_array = WIN_ListChildren( client ))) return 0;
874 875 876

    /* remove all the windows we don't want */
    for (i = total = 0; win_array[i]; i++)
Alexandre Julliard's avatar
Alexandre Julliard committed
877
    {
878 879 880 881 882 883 884 885
        if (!IsWindowVisible( win_array[i] )) continue;
        if (GetWindow( win_array[i], GW_OWNER )) continue; /* skip owned windows */
        if (IsIconic( win_array[i] ))
        {
            has_icons = TRUE;
            continue;
        }
        win_array[total++] = win_array[i];
Alexandre Julliard's avatar
Alexandre Julliard committed
886
    }
887
    win_array[total] = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
888

889 890 891 892 893 894 895 896 897
    if (total)
    {
        INT delta = 0, n = 0, i;
        POINT pos[2];
        if (has_icons) delta = GetSystemMetrics(SM_CYICONSPACING) + GetSystemMetrics(SM_CYICON);

        /* walk the list (backwards) and move windows */
        for (i = total - 1; i >= 0; i--)
        {
898
            TRACE("move %p to (%ld,%ld) size [%ld,%ld]\n",
899 900 901 902 903 904 905
                  win_array[i], pos[0].x, pos[0].y, pos[1].x, pos[1].y);

            MDI_CalcDefaultChildPos(client, n++, pos, delta);
            SetWindowPos( win_array[i], 0, pos[0].x, pos[0].y, pos[1].x, pos[1].y,
                          SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
        }
    }
906
    HeapFree( GetProcessHeap(), 0, win_array );
907 908

    if (has_icons) ArrangeIconicWindows( client );
Alexandre Julliard's avatar
Alexandre Julliard committed
909 910 911
    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
912 913 914
/**********************************************************************
 *					MDITile
 */
915
static void MDITile( HWND client, MDICLIENTINFO *ci, WPARAM wParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
916
{
917 918 919
    HWND *win_array;
    int i, total;
    BOOL has_icons = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
920

Alexandre Julliard's avatar
Alexandre Julliard committed
921
    if (ci->hwndChildMaximized)
922
        SendMessageA( client, WM_MDIRESTORE, (WPARAM)ci->hwndChildMaximized, 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
923

Alexandre Julliard's avatar
Alexandre Julliard committed
924
    if (ci->nActiveChildren == 0) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
925

926
    if (!(win_array = WIN_ListChildren( client ))) return;
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941

    /* remove all the windows we don't want */
    for (i = total = 0; win_array[i]; i++)
    {
        if (!IsWindowVisible( win_array[i] )) continue;
        if (GetWindow( win_array[i], GW_OWNER )) continue; /* skip owned windows (icon titles) */
        if (IsIconic( win_array[i] ))
        {
            has_icons = TRUE;
            continue;
        }
        if ((wParam & MDITILE_SKIPDISABLED) && !IsWindowEnabled( win_array[i] )) continue;
        win_array[total++] = win_array[i];
    }
    win_array[total] = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
942

943
    TRACE("%u windows to tile\n", total);
Alexandre Julliard's avatar
Alexandre Julliard committed
944

945
    if (total)
Alexandre Julliard's avatar
Alexandre Julliard committed
946
    {
947 948 949 950
        HWND *pWnd = win_array;
        RECT rect;
        int x, y, xsize, ysize;
        int rows, columns, r, c, i;
Alexandre Julliard's avatar
Alexandre Julliard committed
951

952 953 954
        GetClientRect(client,&rect);
        rows    = (int) sqrt((double)total);
        columns = total / rows;
Alexandre Julliard's avatar
Alexandre Julliard committed
955

956 957 958 959 960 961
        if( wParam & MDITILE_HORIZONTAL )  /* version >= 3.1 */
        {
            i = rows;
            rows = columns;  /* exchange r and c */
            columns = i;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
962

963 964 965 966 967
        if (has_icons)
        {
            y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
            rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
968

969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989
        ysize   = rect.bottom / rows;
        xsize   = rect.right  / columns;

        for (x = i = 0, c = 1; c <= columns && *pWnd; c++)
        {
            if (c == columns)
            {
                rows  = total - i;
                ysize = rect.bottom / rows;
            }

            y = 0;
            for (r = 1; r <= rows && *pWnd; r++, i++)
            {
                SetWindowPos(*pWnd, 0, x, y, xsize, ysize,
                             SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
                y += ysize;
                pWnd++;
            }
            x += xsize;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
990
    }
991
    HeapFree( GetProcessHeap(), 0, win_array );
992
    if (has_icons) ArrangeIconicWindows( client );
Alexandre Julliard's avatar
Alexandre Julliard committed
993
}
Alexandre Julliard's avatar
Alexandre Julliard committed
994

Alexandre Julliard's avatar
Alexandre Julliard committed
995
/* ----------------------- Frame window ---------------------------- */
Alexandre Julliard's avatar
Alexandre Julliard committed
996

Alexandre Julliard's avatar
Alexandre Julliard committed
997

Alexandre Julliard's avatar
Alexandre Julliard committed
998 999 1000
/**********************************************************************
 *					MDI_AugmentFrameMenu
 */
1001
static BOOL MDI_AugmentFrameMenu( HWND frame, HWND hChild )
Alexandre Julliard's avatar
Alexandre Julliard committed
1002
{
1003
    HMENU menu = GetMenu( frame );
Alexandre Julliard's avatar
Alexandre Julliard committed
1004
    WND*	child = WIN_FindWndPtr(hChild);
1005
    HMENU  	hSysPopup = 0;
1006
  HBITMAP hSysMenuBitmap = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1007

1008
    TRACE("frame %p,child %p\n",frame,hChild);
Alexandre Julliard's avatar
Alexandre Julliard committed
1009

1010
    if( !menu || !child->hSysMenu )
1011 1012 1013 1014 1015
    {
        WIN_ReleaseWndPtr(child);
        return 0;
    }
    WIN_ReleaseWndPtr(child);
Alexandre Julliard's avatar
Alexandre Julliard committed
1016

Alexandre Julliard's avatar
Alexandre Julliard committed
1017
    /* create a copy of sysmenu popup and insert it into frame menu bar */
Alexandre Julliard's avatar
Alexandre Julliard committed
1018

1019
    if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
Alexandre Julliard's avatar
Alexandre Julliard committed
1020
	return 0;
1021 1022

    AppendMenuA(menu,MF_HELP | MF_BITMAP,
1023
                   SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
1024
    AppendMenuA(menu,MF_HELP | MF_BITMAP,
1025
                   SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
1026

1027 1028 1029 1030
  /* In Win 95 look, the system menu is replaced by the child icon */

  if(TWEAK_WineLook > WIN31_LOOK)
  {
1031
    HICON hIcon = (HICON)GetClassLongA(hChild, GCL_HICONSM);
1032
    if (!hIcon)
1033
      hIcon = (HICON)GetClassLongA(hChild, GCL_HICON);
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062
    if (hIcon)
    {
      HDC hMemDC;
      HBITMAP hBitmap, hOldBitmap;
      HBRUSH hBrush;
      HDC hdc = GetDC(hChild);

      if (hdc)
      {
        int cx, cy;
        cx = GetSystemMetrics(SM_CXSMICON);
        cy = GetSystemMetrics(SM_CYSMICON);
        hMemDC = CreateCompatibleDC(hdc);
        hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
        hOldBitmap = SelectObject(hMemDC, hBitmap);
        SetMapMode(hMemDC, MM_TEXT);
        hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
        DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
        SelectObject (hMemDC, hOldBitmap);
        DeleteObject(hBrush);
        DeleteDC(hMemDC);
        ReleaseDC(hChild, hdc);
        hSysMenuBitmap = hBitmap;
      }
    }
  }
  else
    hSysMenuBitmap = hBmpClose;

1063
    if( !InsertMenuA(menu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
1064
                     (UINT_PTR)hSysPopup, (LPSTR)hSysMenuBitmap))
1065
    {
1066
        TRACE("not inserted\n");
1067 1068
	DestroyMenu(hSysPopup);
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1069
    }
1070

1071
    /* The close button is only present in Win 95 look */
1072 1073
    if(TWEAK_WineLook > WIN31_LOOK)
    {
1074
        AppendMenuA(menu,MF_HELP | MF_BITMAP,
1075
                       SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
1076
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1077

1078 1079 1080
    EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
    EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
    EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
1081
    SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1082

Alexandre Julliard's avatar
Alexandre Julliard committed
1083
    /* redraw menu */
1084
    DrawMenuBar(frame);
Alexandre Julliard's avatar
Alexandre Julliard committed
1085

Alexandre Julliard's avatar
Alexandre Julliard committed
1086
    return 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1087 1088 1089
}

/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1090
 *					MDI_RestoreFrameMenu
Alexandre Julliard's avatar
Alexandre Julliard committed
1091
 */
1092
static BOOL MDI_RestoreFrameMenu( HWND frame, HWND hChild )
Alexandre Julliard's avatar
Alexandre Julliard committed
1093
{
1094
    MENUITEMINFOW menuInfo;
1095 1096 1097
    HMENU menu = GetMenu( frame );
    INT nItems = GetMenuItemCount(menu) - 1;
    UINT iId = GetMenuItemID(menu,nItems) ;
Alexandre Julliard's avatar
Alexandre Julliard committed
1098

1099
    TRACE("frame %p,child %p,nIt=%d,iId=%d\n",frame,hChild,nItems,iId);
Alexandre Julliard's avatar
Alexandre Julliard committed
1100

1101
    if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
1102
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1103

1104 1105 1106 1107
    /*
     * Remove the system menu, If that menu is the icon of the window
     * as it is in win95, we have to delete the bitmap.
     */
1108 1109
    memset(&menuInfo, 0, sizeof(menuInfo));
    menuInfo.cbSize = sizeof(menuInfo);
1110 1111
    menuInfo.fMask  = MIIM_DATA | MIIM_TYPE;

1112
    GetMenuItemInfoW(menu,
1113
		     0,
1114 1115 1116
		     TRUE,
		     &menuInfo);

1117
    RemoveMenu(menu,0,MF_BYPOSITION);
1118

1119 1120
    if ( (menuInfo.fType & MFT_BITMAP)           &&
	 (LOWORD(menuInfo.dwTypeData)!=0)        &&
1121
	 (LOWORD(menuInfo.dwTypeData)!=HBITMAP_16(hBmpClose)) )
1122
    {
1123
        DeleteObject(HBITMAP_32(LOWORD(menuInfo.dwTypeData)));
1124 1125
    }

1126 1127
    if(TWEAK_WineLook > WIN31_LOOK)
    {
1128
        /* close */
1129
        DeleteMenu(menu,GetMenuItemCount(menu) - 1,MF_BYPOSITION);
1130
    }
1131
    /* restore */
1132
    DeleteMenu(menu,GetMenuItemCount(menu) - 1,MF_BYPOSITION);
1133
    /* minimize */
1134
    DeleteMenu(menu,GetMenuItemCount(menu) - 1,MF_BYPOSITION);
1135

1136
    DrawMenuBar(frame);
Alexandre Julliard's avatar
Alexandre Julliard committed
1137

Alexandre Julliard's avatar
Alexandre Julliard committed
1138
    return 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1139 1140
}

1141

Alexandre Julliard's avatar
Alexandre Julliard committed
1142
/**********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1143 1144
 *				        MDI_UpdateFrameText
 *
1145
 * used when child window is maximized/restored
Alexandre Julliard's avatar
Alexandre Julliard committed
1146 1147
 *
 * Note: lpTitle can be NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
1148
 */
1149
static void MDI_UpdateFrameText( HWND frame, HWND hClient,
1150
                                 BOOL repaint, LPCWSTR lpTitle )
Alexandre Julliard's avatar
Alexandre Julliard committed
1151
{
1152
    WCHAR   lpBuffer[MDI_MAXTITLELENGTH+1];
1153
    MDICLIENTINFO *ci = get_client_info( hClient );
Alexandre Julliard's avatar
Alexandre Julliard committed
1154

1155
    TRACE("repaint %i, frameText %s\n", repaint, debugstr_w(lpTitle));
Alexandre Julliard's avatar
Alexandre Julliard committed
1156

1157
    if (!ci) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1158

1159
    if (!lpTitle && !ci->frameTitle)  /* first time around, get title from the frame window */
1160
    {
1161 1162
        GetWindowTextW( frame, lpBuffer, sizeof(lpBuffer)/sizeof(WCHAR) );
        lpTitle = lpBuffer;
1163
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1164

Alexandre Julliard's avatar
Alexandre Julliard committed
1165
    /* store new "default" title if lpTitle is not NULL */
1166
    if (lpTitle)
Alexandre Julliard's avatar
Alexandre Julliard committed
1167
    {
1168
	if (ci->frameTitle) HeapFree( GetProcessHeap(), 0, ci->frameTitle );
1169 1170
	if ((ci->frameTitle = HeapAlloc( GetProcessHeap(), 0, (strlenW(lpTitle)+1)*sizeof(WCHAR))))
            strcpyW( ci->frameTitle, lpTitle );
Alexandre Julliard's avatar
Alexandre Julliard committed
1171 1172 1173 1174
    }

    if (ci->frameTitle)
    {
1175
	if (ci->hwndChildMaximized)
Alexandre Julliard's avatar
Alexandre Julliard committed
1176 1177 1178
	{
	    /* combine frame title and child title if possible */

1179 1180
	    static const WCHAR lpBracket[]  = {' ','-',' ','[',0};
	    static const WCHAR lpBracket2[]  = {']',0};
1181
	    int	i_frame_text_length = strlenW(ci->frameTitle);
Alexandre Julliard's avatar
Alexandre Julliard committed
1182

1183
	    lstrcpynW( lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH);
Alexandre Julliard's avatar
Alexandre Julliard committed
1184 1185 1186

	    if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
            {
1187
		strcatW( lpBuffer, lpBracket );
1188 1189 1190 1191 1192 1193
                if (GetWindowTextW( ci->hwndChildMaximized, lpBuffer + i_frame_text_length + 4,
                                    MDI_MAXTITLELENGTH - i_frame_text_length - 5 ))
                    strcatW( lpBuffer, lpBracket2 );
                else
                    lpBuffer[i_frame_text_length] = 0;  /* remove bracket */
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
1194 1195 1196
	}
	else
	{
1197
            lstrcpynW(lpBuffer, ci->frameTitle, MDI_MAXTITLELENGTH+1 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1198 1199 1200 1201 1202
	}
    }
    else
	lpBuffer[0] = '\0';

1203
    DefWindowProcW( frame, WM_SETTEXT, 0, (LPARAM)lpBuffer );
Alexandre Julliard's avatar
Alexandre Julliard committed
1204
    if( repaint == MDI_REPAINTFRAME)
1205 1206
        SetWindowPos( frame, 0,0,0,0,0, SWP_FRAMECHANGED |
                      SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
Alexandre Julliard's avatar
Alexandre Julliard committed
1207
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1208 1209


Alexandre Julliard's avatar
Alexandre Julliard committed
1210
/* ----------------------------- Interface ---------------------------- */
Alexandre Julliard's avatar
Alexandre Julliard committed
1211 1212


Alexandre Julliard's avatar
Alexandre Julliard committed
1213
/**********************************************************************
1214
 *		MDIClientWndProc_common
Alexandre Julliard's avatar
Alexandre Julliard committed
1215
 */
1216 1217
static LRESULT MDIClientWndProc_common( HWND hwnd, UINT message,
                                        WPARAM wParam, LPARAM lParam, BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
1218
{
1219
    MDICLIENTINFO *ci;
1220

1221
    if (!(ci = get_client_info( hwnd ))) return 0;
1222

Alexandre Julliard's avatar
Alexandre Julliard committed
1223 1224 1225
    switch (message)
    {
      case WM_CREATE:
1226 1227 1228 1229 1230
      {
          RECT rect;
          /* Since we are using only cs->lpCreateParams, we can safely
           * cast to LPCREATESTRUCTA here */
          LPCREATESTRUCTA cs = (LPCREATESTRUCTA)lParam;
1231
          WND *wndPtr = WIN_GetPtr( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1232 1233 1234 1235

	/* Translation layer doesn't know what's in the cs->lpCreateParams
	 * so we have to keep track of what environment we're in. */

1236
	if( wndPtr->flags & WIN_ISWIN32 )
Alexandre Julliard's avatar
Alexandre Julliard committed
1237
	{
1238
#define ccs ((LPCLIENTCREATESTRUCT)cs->lpCreateParams)
Alexandre Julliard's avatar
Alexandre Julliard committed
1239 1240 1241 1242
	    ci->hWindowMenu	= ccs->hWindowMenu;
	    ci->idFirstChild	= ccs->idFirstChild;
#undef ccs
	}
1243
        else
Alexandre Julliard's avatar
Alexandre Julliard committed
1244
	{
1245
	    LPCLIENTCREATESTRUCT16 ccs = MapSL((SEGPTR)cs->lpCreateParams);
1246
	    ci->hWindowMenu	= HMENU_32(ccs->hWindowMenu);
Alexandre Julliard's avatar
Alexandre Julliard committed
1247 1248
	    ci->idFirstChild	= ccs->idFirstChild;
	}
1249
        WIN_ReleasePtr( wndPtr );
Alexandre Julliard's avatar
Alexandre Julliard committed
1250

Alexandre Julliard's avatar
Alexandre Julliard committed
1251
	ci->hwndChildMaximized  = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1252
	ci->nActiveChildren	= 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1253
	ci->nTotalCreated	= 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1254
	ci->frameTitle		= NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1255
	ci->mdiFlags		= 0;
1256
        SetWindowLongW( hwnd, GWL_STYLE, GetWindowLongW(hwnd,GWL_STYLE) | WS_CLIPCHILDREN );
Alexandre Julliard's avatar
Alexandre Julliard committed
1257

1258
	if (!hBmpClose) hBmpClose = CreateMDIMenuBitmap();
Alexandre Julliard's avatar
Alexandre Julliard committed
1259

1260
	if (ci->hWindowMenu != 0)
1261
	    AppendMenuW( ci->hWindowMenu, MF_SEPARATOR, 0, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
1262

1263 1264 1265 1266
	GetClientRect( GetParent(hwnd), &rect);
        MoveWindow( hwnd, 0, 0, rect.right, rect.bottom, FALSE );

        MDI_UpdateFrameText( GetParent(hwnd), hwnd, MDI_NOFRAMEREPAINT, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
1267

1268
        TRACE("Client created - hwnd = %p, idFirst = %u\n", hwnd, ci->idFirstChild );
1269 1270
        return 0;
      }
Alexandre Julliard's avatar
Alexandre Julliard committed
1271

Alexandre Julliard's avatar
Alexandre Julliard committed
1272
      case WM_DESTROY:
1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287
      {
          INT nItems;
          if( ci->hwndChildMaximized )
              MDI_RestoreFrameMenu( GetParent(hwnd), ci->hwndChildMaximized);
          if((ci->hWindowMenu != 0) &&
             (nItems = GetMenuItemCount(ci->hWindowMenu)) > 0)
          {
              ci->idFirstChild = nItems - 1;
              ci->nActiveChildren++;  /* to delete a separator */
              while( ci->nActiveChildren-- )
                  DeleteMenu(ci->hWindowMenu,MF_BYPOSITION,ci->idFirstChild--);
          }
          if (ci->frameTitle) HeapFree( GetProcessHeap(), 0, ci->frameTitle );
          return 0;
      }
Alexandre Julliard's avatar
Alexandre Julliard committed
1288 1289

      case WM_MDIACTIVATE:
1290 1291
        if( ci->hwndActiveChild != (HWND)wParam )
	    SetWindowPos((HWND)wParam, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
1292
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1293 1294

      case WM_MDICASCADE:
1295
        return MDICascade(hwnd, ci);
Alexandre Julliard's avatar
Alexandre Julliard committed
1296 1297

      case WM_MDICREATE:
1298 1299 1300
        if (lParam)
            return (LRESULT)MDICreateChild( hwnd, ci, (MDICREATESTRUCTA *)lParam, unicode );
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1301 1302

      case WM_MDIDESTROY:
1303
          return MDIDestroyChild( hwnd, ci, WIN_GetFullHandle( (HWND)wParam ), TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1304 1305

      case WM_MDIGETACTIVE:
1306
          if (lParam) *(BOOL *)lParam = (ci->hwndChildMaximized != 0);
1307
          return (LRESULT)ci->hwndActiveChild;
Alexandre Julliard's avatar
Alexandre Julliard committed
1308 1309

      case WM_MDIICONARRANGE:
Alexandre Julliard's avatar
Alexandre Julliard committed
1310
	ci->mdiFlags |= MDIF_NEEDUPDATE;
1311
        ArrangeIconicWindows( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1312
	ci->sbRecalc = SB_BOTH+1;
1313 1314 1315
        SendMessageW( hwnd, WM_MDICALCCHILDSCROLL, 0, 0 );
        return 0;

Alexandre Julliard's avatar
Alexandre Julliard committed
1316
      case WM_MDIMAXIMIZE:
1317
	ShowWindow( (HWND)wParam, SW_MAXIMIZE );
1318
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1319

Alexandre Julliard's avatar
Alexandre Julliard committed
1320
      case WM_MDINEXT: /* lParam != 0 means previous window */
1321
	MDI_SwitchActiveChild( hwnd, WIN_GetFullHandle( (HWND)wParam ), !lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1322
	break;
1323

Alexandre Julliard's avatar
Alexandre Julliard committed
1324
      case WM_MDIRESTORE:
1325 1326
        SendMessageW( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1327 1328

      case WM_MDISETMENU:
1329
          return MDISetMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
1330

Alexandre Julliard's avatar
Alexandre Julliard committed
1331
      case WM_MDIREFRESHMENU:
1332
          return MDIRefreshMenu( hwnd, (HMENU)wParam, (HMENU)lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1333

Alexandre Julliard's avatar
Alexandre Julliard committed
1334
      case WM_MDITILE:
Alexandre Julliard's avatar
Alexandre Julliard committed
1335
	ci->mdiFlags |= MDIF_NEEDUPDATE;
1336 1337
        ShowScrollBar( hwnd, SB_BOTH, FALSE );
        MDITile( hwnd, ci, wParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1338
        ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1339
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1340 1341 1342

      case WM_VSCROLL:
      case WM_HSCROLL:
Alexandre Julliard's avatar
Alexandre Julliard committed
1343
	ci->mdiFlags |= MDIF_NEEDUPDATE;
1344
        ScrollChildren( hwnd, message, wParam, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1345
	ci->mdiFlags &= ~MDIF_NEEDUPDATE;
1346
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1347 1348

      case WM_SETFOCUS:
1349 1350 1351 1352
          if (ci->hwndActiveChild && !IsIconic( ci->hwndActiveChild ))
              SetFocus( ci->hwndActiveChild );
          return 0;

Alexandre Julliard's avatar
Alexandre Julliard committed
1353
      case WM_NCACTIVATE:
Alexandre Julliard's avatar
Alexandre Julliard committed
1354
        if( ci->hwndActiveChild )
1355
            SendMessageW(ci->hwndActiveChild, message, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1356
	break;
1357

Alexandre Julliard's avatar
Alexandre Julliard committed
1358
      case WM_PARENTNOTIFY:
Alexandre Julliard's avatar
Alexandre Julliard committed
1359
        if (LOWORD(wParam) == WM_LBUTTONDOWN)
Alexandre Julliard's avatar
Alexandre Julliard committed
1360
        {
1361 1362 1363 1364
            HWND child;
            POINT pt;
            pt.x = SLOWORD(lParam);
            pt.y = SHIWORD(lParam);
1365
            child = ChildWindowFromPoint(hwnd, pt);
Alexandre Julliard's avatar
Alexandre Julliard committed
1366

1367
	    TRACE("notification from %p (%li,%li)\n",child,pt.x,pt.y);
Alexandre Julliard's avatar
Alexandre Julliard committed
1368

1369
            if( child && child != hwnd && child != ci->hwndActiveChild )
1370
                SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1371
        }
1372
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1373 1374

      case WM_SIZE:
1375
        if( IsWindow(ci->hwndChildMaximized) )
Alexandre Julliard's avatar
Alexandre Julliard committed
1376
	{
1377 1378 1379 1380 1381 1382
	    RECT	rect;

	    rect.left = 0;
	    rect.top = 0;
	    rect.right = LOWORD(lParam);
	    rect.bottom = HIWORD(lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1383

1384 1385
	    AdjustWindowRectEx(&rect, GetWindowLongA(ci->hwndChildMaximized,GWL_STYLE),
                               0, GetWindowLongA(ci->hwndChildMaximized,GWL_EXSTYLE) );
1386
	    MoveWindow(ci->hwndChildMaximized, rect.left, rect.top,
Alexandre Julliard's avatar
Alexandre Julliard committed
1387 1388
			 rect.right - rect.left, rect.bottom - rect.top, 1);
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
1389
	else
1390
            MDI_PostUpdate(hwnd, ci, SB_BOTH+1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1391

Alexandre Julliard's avatar
Alexandre Julliard committed
1392 1393
	break;

Alexandre Julliard's avatar
Alexandre Julliard committed
1394
      case WM_MDICALCCHILDSCROLL:
Alexandre Julliard's avatar
Alexandre Julliard committed
1395 1396
	if( (ci->mdiFlags & MDIF_NEEDUPDATE) && ci->sbRecalc )
	{
1397
            CalcChildScroll(hwnd, ci->sbRecalc-1);
Alexandre Julliard's avatar
Alexandre Julliard committed
1398 1399 1400
	    ci->sbRecalc = 0;
	    ci->mdiFlags &= ~MDIF_NEEDUPDATE;
	}
1401
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1402
    }
1403 1404
    return unicode ? DefWindowProcW( hwnd, message, wParam, lParam ) :
                     DefWindowProcA( hwnd, message, wParam, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1405 1406
}

1407 1408 1409 1410 1411
/***********************************************************************
 *		MDIClientWndProcA
 */
static LRESULT WINAPI MDIClientWndProcA( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
1412 1413
    if (!IsWindow(hwnd)) return 0;
    return MDIClientWndProc_common( hwnd, message, wParam, lParam, FALSE );
1414 1415 1416 1417 1418 1419 1420
}

/***********************************************************************
 *		MDIClientWndProcW
 */
static LRESULT WINAPI MDIClientWndProcW( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
1421 1422
    if (!IsWindow(hwnd)) return 0;
    return MDIClientWndProc_common( hwnd, message, wParam, lParam, TRUE );
1423
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1424 1425

/***********************************************************************
1426
 *		DefFrameProc (USER.445)
Alexandre Julliard's avatar
Alexandre Julliard committed
1427
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1428 1429
LRESULT WINAPI DefFrameProc16( HWND16 hwnd, HWND16 hwndMDIClient,
                               UINT16 message, WPARAM16 wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1430
{
1431
    switch (message)
Alexandre Julliard's avatar
Alexandre Julliard committed
1432
    {
1433
    case WM_SETTEXT:
1434 1435
        lParam = (LPARAM)MapSL(lParam);
        /* fall through */
1436 1437 1438 1439
    case WM_COMMAND:
    case WM_NCACTIVATE:
    case WM_SETFOCUS:
    case WM_SIZE:
1440 1441
        return DefFrameProcA( WIN_Handle32(hwnd), WIN_Handle32(hwndMDIClient),
                              message, wParam, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1442

1443 1444 1445
    case WM_NEXTMENU:
        {
            MDINEXTMENU next_menu;
1446 1447
            DefFrameProcW( WIN_Handle32(hwnd), WIN_Handle32(hwndMDIClient),
                           message, wParam, (LPARAM)&next_menu );
1448
            return MAKELONG( HMENU_16(next_menu.hmenuNext), HWND_16(next_menu.hwndNext) );
1449 1450 1451
        }
    default:
        return DefWindowProc16(hwnd, message, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1452 1453 1454
    }
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1455 1456

/***********************************************************************
1457
 *		DefFrameProcA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1458
 */
1459 1460
LRESULT WINAPI DefFrameProcA( HWND hwnd, HWND hwndMDIClient,
                                UINT message, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1461 1462 1463 1464 1465
{
    if (hwndMDIClient)
    {
	switch (message)
	{
1466 1467
        case WM_SETTEXT:
            {
1468 1469 1470
                DWORD len = MultiByteToWideChar( CP_ACP, 0, (LPSTR)lParam, -1, NULL, 0 );
                LPWSTR text = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
                MultiByteToWideChar( CP_ACP, 0, (LPSTR)lParam, -1, text, len );
1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482
                MDI_UpdateFrameText(hwnd, hwndMDIClient, MDI_REPAINTFRAME, text );
                HeapFree( GetProcessHeap(), 0, text );
            }
            return 1; /* success. FIXME: check text length */

        case WM_COMMAND:
        case WM_NCACTIVATE:
        case WM_NEXTMENU:
        case WM_SETFOCUS:
        case WM_SIZE:
            return DefFrameProcW( hwnd, hwndMDIClient, message, wParam, lParam );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1483
    }
1484
    return DefWindowProcA(hwnd, message, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1485 1486 1487 1488
}


/***********************************************************************
1489
 *		DefFrameProcW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1490
 */
1491 1492
LRESULT WINAPI DefFrameProcW( HWND hwnd, HWND hwndMDIClient,
                                UINT message, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1493
{
1494 1495 1496
    MDICLIENTINFO *ci = get_client_info( hwndMDIClient );

    if (ci)
Alexandre Julliard's avatar
Alexandre Julliard committed
1497 1498 1499
    {
	switch (message)
	{
1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526
        case WM_COMMAND:
            {
                WORD id = LOWORD(wParam);
                /* check for possible syscommands for maximized MDI child */
                if (id <  ci->idFirstChild || id >= ci->idFirstChild + ci->nActiveChildren)
                {
                    if( (id - 0xf000) & 0xf00f ) break;
                    if( !ci->hwndChildMaximized ) break;
                    switch( id )
                    {
                    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);
                    }
                }
                else
                {
                    HWND childHwnd;
                    if (id - ci->idFirstChild == MDI_MOREWINDOWSLIMIT)
                        /* User chose "More Windows..." */
1527
                        childHwnd = MDI_MoreWindowsDialog(hwndMDIClient);
1528 1529 1530 1531 1532 1533 1534 1535 1536
                    else
                        /* User chose one of the windows listed in the "Windows" menu */
                        childHwnd = MDI_GetChildByID(hwndMDIClient,id);

                    if( childHwnd )
                        SendMessageW( hwndMDIClient, WM_MDIACTIVATE, (WPARAM)childHwnd, 0 );
                }
            }
            break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1537

1538
        case WM_NCACTIVATE:
1539
	    SendMessageW(hwndMDIClient, message, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1540 1541
	    break;

1542
        case WM_SETTEXT:
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
            MDI_UpdateFrameText(hwnd, hwndMDIClient, MDI_REPAINTFRAME, (LPWSTR)lParam );
	    return 1; /* success. FIXME: check text length */

        case WM_SETFOCUS:
	    SetFocus(hwndMDIClient);
	    break;

        case WM_SIZE:
            MoveWindow(hwndMDIClient, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
            break;

        case WM_NEXTMENU:
            {
                MDINEXTMENU *next_menu = (MDINEXTMENU *)lParam;

                if (!IsIconic(hwnd) && ci->hwndActiveChild && !ci->hwndChildMaximized)
                {
1560
                    /* control menu is between the frame system menu and
1561
                     * the first entry of menu bar */
1562
                    WND *wndPtr = WIN_GetPtr(hwnd);
1563 1564 1565 1566

                    if( (wParam == VK_LEFT && GetMenu(hwnd) == next_menu->hmenuIn) ||
                        (wParam == VK_RIGHT && GetSubMenu(wndPtr->hSysMenu, 0) == next_menu->hmenuIn) )
                    {
1567 1568
                        WIN_ReleasePtr(wndPtr);
                        wndPtr = WIN_GetPtr(ci->hwndActiveChild);
1569 1570 1571
                        next_menu->hmenuNext = GetSubMenu(wndPtr->hSysMenu, 0);
                        next_menu->hwndNext = ci->hwndActiveChild;
                    }
1572
                    WIN_ReleasePtr(wndPtr);
1573 1574 1575
                }
                return 0;
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
1576 1577
	}
    }
1578

1579
    return DefWindowProcW( hwnd, message, wParam, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1580 1581 1582 1583
}


/***********************************************************************
1584
 *		DefMDIChildProc (USER.447)
Alexandre Julliard's avatar
Alexandre Julliard committed
1585
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
1586 1587
LRESULT WINAPI DefMDIChildProc16( HWND16 hwnd, UINT16 message,
                                  WPARAM16 wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1588 1589 1590
{
    switch (message)
    {
1591
    case WM_SETTEXT:
1592
        return DefMDIChildProcA( WIN_Handle32(hwnd), message, wParam, (LPARAM)MapSL(lParam) );
1593 1594 1595 1596 1597 1598 1599 1600
    case WM_MENUCHAR:
    case WM_CLOSE:
    case WM_SETFOCUS:
    case WM_CHILDACTIVATE:
    case WM_SYSCOMMAND:
    case WM_SETVISIBLE:
    case WM_SIZE:
    case WM_SYSCHAR:
1601
        return DefMDIChildProcW( WIN_Handle32(hwnd), message, wParam, lParam );
1602
    case WM_GETMINMAXINFO:
1603
        {
1604 1605 1606
            MINMAXINFO16 *mmi16 = (MINMAXINFO16 *)MapSL(lParam);
            MINMAXINFO mmi;
            STRUCT32_MINMAXINFO16to32( mmi16, &mmi );
1607
            DefMDIChildProcW( WIN_Handle32(hwnd), message, wParam, (LPARAM)&mmi );
1608 1609
            STRUCT32_MINMAXINFO32to16( &mmi, mmi16 );
            return 0;
1610
        }
1611
    case WM_NEXTMENU:
1612
        {
1613
            MDINEXTMENU next_menu;
1614
            DefMDIChildProcW( WIN_Handle32(hwnd), message, wParam, (LPARAM)&next_menu );
1615
            return MAKELONG( HMENU_16(next_menu.hmenuNext), HWND_16(next_menu.hwndNext) );
1616
        }
1617 1618
    default:
        return DefWindowProc16(hwnd, message, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1619 1620 1621
    }
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1622 1623

/***********************************************************************
1624
 *		DefMDIChildProcA (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1625
 */
1626 1627
LRESULT WINAPI DefMDIChildProcA( HWND hwnd, UINT message,
                                   WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1628
{
1629 1630 1631
    HWND client = GetParent(hwnd);
    MDICLIENTINFO *ci = get_client_info( client );

1632
    hwnd = WIN_GetFullHandle( hwnd );
1633
    if (!ci) return DefWindowProcA( hwnd, message, wParam, lParam );
1634

Alexandre Julliard's avatar
Alexandre Julliard committed
1635 1636
    switch (message)
    {
1637
    case WM_SETTEXT:
1638
	DefWindowProcA(hwnd, message, wParam, lParam);
1639
        MDI_MenuModifyItem( client, hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1640
	if( ci->hwndChildMaximized == hwnd )
1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654
	    MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL );
        return 1; /* success. FIXME: check text length */

    case WM_GETMINMAXINFO:
    case WM_MENUCHAR:
    case WM_CLOSE:
    case WM_SETFOCUS:
    case WM_CHILDACTIVATE:
    case WM_SYSCOMMAND:
    case WM_SETVISIBLE:
    case WM_SIZE:
    case WM_NEXTMENU:
    case WM_SYSCHAR:
        return DefMDIChildProcW( hwnd, message, wParam, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1655
    }
1656
    return DefWindowProcA(hwnd, message, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1657 1658 1659 1660
}


/***********************************************************************
1661
 *		DefMDIChildProcW (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1662
 */
1663 1664
LRESULT WINAPI DefMDIChildProcW( HWND hwnd, UINT message,
                                   WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1665
{
1666 1667 1668
    HWND client = GetParent(hwnd);
    MDICLIENTINFO *ci = get_client_info( client );

1669
    hwnd = WIN_GetFullHandle( hwnd );
1670
    if (!ci) return DefWindowProcW( hwnd, message, wParam, lParam );
1671

Alexandre Julliard's avatar
Alexandre Julliard committed
1672 1673
    switch (message)
    {
1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707
    case WM_SETTEXT:
        DefWindowProcW(hwnd, message, wParam, lParam);
        MDI_MenuModifyItem( client, hwnd );
        if( ci->hwndChildMaximized == hwnd )
            MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL );
        return 1; /* success. FIXME: check text length */

    case WM_GETMINMAXINFO:
        MDI_ChildGetMinMaxInfo( client, hwnd, (MINMAXINFO *)lParam );
        return 0;

    case WM_MENUCHAR:
        return 0x00010000; /* MDI children don't have menu bars */

    case WM_CLOSE:
        SendMessageW( client, WM_MDIDESTROY, (WPARAM)hwnd, 0 );
        return 0;

    case WM_SETFOCUS:
        if (ci->hwndActiveChild != hwnd) MDI_ChildActivate( client, hwnd );
        break;

    case WM_CHILDACTIVATE:
        MDI_ChildActivate( client, hwnd );
        return 0;

    case WM_SYSCOMMAND:
        switch( wParam )
        {
        case SC_MOVE:
            if( ci->hwndChildMaximized == hwnd) return 0;
            break;
        case SC_RESTORE:
        case SC_MINIMIZE:
1708 1709
            SetWindowLongW( hwnd, GWL_STYLE,
                            GetWindowLongW( hwnd, GWL_STYLE ) | WS_SYSMENU );
1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750
            break;
        case SC_MAXIMIZE:
            if (ci->hwndChildMaximized == hwnd)
                return SendMessageW( GetParent(client), message, wParam, lParam);
            SetWindowLongW( hwnd, GWL_STYLE,
                            GetWindowLongW( hwnd, GWL_STYLE ) & ~WS_SYSMENU );
            break;
        case SC_NEXTWINDOW:
            SendMessageW( client, WM_MDINEXT, 0, 0);
            return 0;
        case SC_PREVWINDOW:
            SendMessageW( client, WM_MDINEXT, 0, 1);
            return 0;
        }
        break;

    case WM_SETVISIBLE:
        if( ci->hwndChildMaximized) ci->mdiFlags &= ~MDIF_NEEDUPDATE;
        else MDI_PostUpdate(client, ci, SB_BOTH+1);
        break;

    case WM_SIZE:
        if( ci->hwndActiveChild == hwnd && wParam != SIZE_MAXIMIZED )
        {
            ci->hwndChildMaximized = 0;
            MDI_RestoreFrameMenu( GetParent(client), hwnd );
            MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL );
        }

        if( wParam == SIZE_MAXIMIZED )
        {
            HWND hMaxChild = ci->hwndChildMaximized;

            if( hMaxChild == hwnd ) break;
            if( hMaxChild)
            {
                SendMessageW( hMaxChild, WM_SETREDRAW, FALSE, 0 );
                MDI_RestoreFrameMenu( GetParent(client), hMaxChild );
                ShowWindow( hMaxChild, SW_SHOWNOACTIVATE );
                SendMessageW( hMaxChild, WM_SETREDRAW, TRUE, 0 );
            }
1751
            TRACE("maximizing child %p\n", hwnd );
1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777

            /* keep track of the maximized window. */
            ci->hwndChildMaximized = hwnd; /* !!! */

            /* The maximized window should also be the active window */
            MDI_ChildActivate( client, hwnd );
            MDI_AugmentFrameMenu( GetParent(client), hwnd );
            MDI_UpdateFrameText( GetParent(client), client, MDI_REPAINTFRAME, NULL );
        }

        if( wParam == SIZE_MINIMIZED )
        {
            HWND switchTo = MDI_GetWindow(ci, hwnd, TRUE, WS_MINIMIZE);

            if (switchTo) SendMessageW( switchTo, WM_CHILDACTIVATE, 0, 0);
        }
        MDI_PostUpdate(client, ci, SB_BOTH+1);
        break;

    case WM_NEXTMENU:
        {
            MDINEXTMENU *next_menu = (MDINEXTMENU *)lParam;
            HWND parent = GetParent(client);

            if( wParam == VK_LEFT )  /* switch to frame system menu */
            {
1778
                WND *wndPtr = WIN_GetPtr( parent );
1779
                next_menu->hmenuNext = GetSubMenu( wndPtr->hSysMenu, 0 );
1780
                WIN_ReleasePtr( wndPtr );
1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796
            }
            if( wParam == VK_RIGHT )  /* to frame menu bar */
            {
                next_menu->hmenuNext = GetMenu(parent);
            }
            next_menu->hwndNext = parent;
            return 0;
        }

    case WM_SYSCHAR:
        if (wParam == '-')
        {
            SendMessageW( hwnd, WM_SYSCOMMAND, (WPARAM)SC_KEYMENU, (DWORD)VK_SPACE);
            return 0;
        }
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1797
    }
1798
    return DefWindowProcW(hwnd, message, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1799 1800
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1801
/**********************************************************************
1802
 *		CreateMDIWindowA (USER32.@) Creates a MDI child
1803 1804 1805 1806
 *
 * RETURNS
 *    Success: Handle to created window
 *    Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
1807
 */
1808
HWND WINAPI CreateMDIWindowA(
1809 1810 1811
    LPCSTR lpClassName,    /* [in] Pointer to registered child class name */
    LPCSTR lpWindowName,   /* [in] Pointer to window name */
    DWORD dwStyle,         /* [in] Window style */
1812 1813 1814 1815 1816 1817
    INT X,               /* [in] Horizontal position of window */
    INT Y,               /* [in] Vertical position of window */
    INT nWidth,          /* [in] Width of window */
    INT nHeight,         /* [in] Height of window */
    HWND hWndParent,     /* [in] Handle to parent window */
    HINSTANCE hInstance, /* [in] Handle to application instance */
1818
    LPARAM lParam)         /* [in] Application-defined value */
Alexandre Julliard's avatar
Alexandre Julliard committed
1819
{
1820
    MDICLIENTINFO *pCi = get_client_info( hWndParent );
1821
    MDICREATESTRUCTA cs;
Alexandre Julliard's avatar
Alexandre Julliard committed
1822

1823
    TRACE("(%s,%s,%ld,%d,%d,%d,%d,%p,%p,%ld)\n",
1824 1825
          debugstr_a(lpClassName),debugstr_a(lpWindowName),dwStyle,X,Y,
          nWidth,nHeight,hWndParent,hInstance,lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1826

1827
    if (!pCi)
1828
    {
1829
        ERR("bad hwnd for MDI-client: %p\n", hWndParent);
1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841
        return 0;
    }
    cs.szClass=lpClassName;
    cs.szTitle=lpWindowName;
    cs.hOwner=hInstance;
    cs.x=X;
    cs.y=Y;
    cs.cx=nWidth;
    cs.cy=nHeight;
    cs.style=dwStyle;
    cs.lParam=lParam;

1842
    return MDICreateChild(hWndParent, pCi, &cs, FALSE);
1843 1844
}

1845
/***********************************************************************
1846
 *		CreateMDIWindowW (USER32.@) Creates a MDI child
Alexandre Julliard's avatar
Alexandre Julliard committed
1847 1848 1849 1850
 *
 * RETURNS
 *    Success: Handle to created window
 *    Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
1851
 */
1852
HWND WINAPI CreateMDIWindowW(
1853 1854 1855
    LPCWSTR lpClassName,    /* [in] Pointer to registered child class name */
    LPCWSTR lpWindowName,   /* [in] Pointer to window name */
    DWORD dwStyle,         /* [in] Window style */
1856 1857 1858 1859 1860 1861
    INT X,               /* [in] Horizontal position of window */
    INT Y,               /* [in] Vertical position of window */
    INT nWidth,          /* [in] Width of window */
    INT nHeight,         /* [in] Height of window */
    HWND hWndParent,     /* [in] Handle to parent window */
    HINSTANCE hInstance, /* [in] Handle to application instance */
1862 1863
    LPARAM lParam)         /* [in] Application-defined value */
{
1864
    MDICLIENTINFO *pCi = get_client_info( hWndParent );
1865
    MDICREATESTRUCTW cs;
1866

1867
    TRACE("(%s,%s,%ld,%d,%d,%d,%d,%p,%p,%ld)\n",
1868 1869
          debugstr_w(lpClassName), debugstr_w(lpWindowName), dwStyle, X, Y,
          nWidth, nHeight, hWndParent, hInstance, lParam);
1870

1871
    if (!pCi)
1872
    {
1873
        ERR("bad hwnd for MDI-client: %p\n", hWndParent);
1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885
        return 0;
    }
    cs.szClass = lpClassName;
    cs.szTitle = lpWindowName;
    cs.hOwner = hInstance;
    cs.x = X;
    cs.y = Y;
    cs.cx = nWidth;
    cs.cy = nHeight;
    cs.style = dwStyle;
    cs.lParam = lParam;

1886
    return MDICreateChild(hWndParent, pCi, (MDICREATESTRUCTA *)&cs, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1887 1888
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1889
/**********************************************************************
1890
 *		TranslateMDISysAccel (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1891
 */
1892
BOOL WINAPI TranslateMDISysAccel( HWND hwndClient, LPMSG msg )
Alexandre Julliard's avatar
Alexandre Julliard committed
1893
{
1894
    if (msg->message == WM_KEYDOWN || msg->message == WM_SYSKEYDOWN)
Alexandre Julliard's avatar
Alexandre Julliard committed
1895
    {
1896 1897
        MDICLIENTINFO *ci = get_client_info( hwndClient );
        WPARAM wParam = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1898

1899
        if (!ci || !IsWindowEnabled(ci->hwndActiveChild)) return 0;
1900

1901
        /* translate if the Ctrl key is down and Alt not. */
1902

1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921
        if( (GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_MENU) & 0x8000))
        {
            switch( msg->wParam )
            {
            case VK_F6:
            case VK_TAB:
                wParam = ( GetKeyState(VK_SHIFT) & 0x8000 ) ? SC_NEXTWINDOW : SC_PREVWINDOW;
                break;
            case VK_F4:
            case VK_RBUTTON:
                wParam = SC_CLOSE;
                break;
            default:
                return 0;
            }
            TRACE("wParam = %04x\n", wParam);
            SendMessageW(ci->hwndActiveChild, WM_SYSCOMMAND, wParam, (LPARAM)msg->wParam);
            return 1;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1922 1923
    }
    return 0; /* failure */
Alexandre Julliard's avatar
Alexandre Julliard committed
1924
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1925

1926 1927 1928 1929
/***********************************************************************
 *		CalcChildScroll (USER32.@)
 */
void WINAPI CalcChildScroll( HWND hwnd, INT scroll )
Alexandre Julliard's avatar
Alexandre Julliard committed
1930
{
1931
    SCROLLINFO info;
1932
    RECT childRect, clientRect;
1933
    HWND *list;
Alexandre Julliard's avatar
Alexandre Julliard committed
1934

1935 1936
    GetClientRect( hwnd, &clientRect );
    SetRectEmpty( &childRect );
Alexandre Julliard's avatar
Alexandre Julliard committed
1937

1938
    if ((list = WIN_ListChildren( hwnd )))
Alexandre Julliard's avatar
Alexandre Julliard committed
1939
    {
1940 1941 1942 1943 1944 1945
        int i;
        for (i = 0; list[i]; i++)
        {
            DWORD style = GetWindowLongW( list[i], GWL_STYLE );
            if (style & WS_MAXIMIZE)
            {
1946
                HeapFree( GetProcessHeap(), 0, list );
1947 1948 1949 1950 1951 1952 1953 1954 1955 1956
                ShowScrollBar( hwnd, SB_BOTH, FALSE );
                return;
            }
            if (style & WS_VISIBLE)
            {
                WND *pWnd = WIN_FindWndPtr( list[i] );
                UnionRect( &childRect, &pWnd->rectWindow, &childRect );
                WIN_ReleaseWndPtr( pWnd );
            }
        }
1957
        HeapFree( GetProcessHeap(), 0, list );
1958
    }
1959
    UnionRect( &childRect, &clientRect, &childRect );
Alexandre Julliard's avatar
Alexandre Julliard committed
1960

1961 1962 1963
    /* set common info values */
    info.cbSize = sizeof(info);
    info.fMask = SIF_POS | SIF_RANGE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1964

1965
    /* set the specific */
Alexandre Julliard's avatar
Alexandre Julliard committed
1966
    switch( scroll )
Alexandre Julliard's avatar
Alexandre Julliard committed
1967
    {
1968
	case SB_BOTH:
Alexandre Julliard's avatar
Alexandre Julliard committed
1969
	case SB_HORZ:
1970 1971 1972 1973 1974 1975
			info.nMin = childRect.left;
			info.nMax = childRect.right - clientRect.right;
			info.nPos = clientRect.left - childRect.left;
			SetScrollInfo(hwnd, scroll, &info, TRUE);
			if (scroll == SB_HORZ) break;
			/* fall through */
Alexandre Julliard's avatar
Alexandre Julliard committed
1976
	case SB_VERT:
1977 1978 1979
			info.nMin = childRect.top;
			info.nMax = childRect.bottom - clientRect.bottom;
			info.nPos = clientRect.top - childRect.top;
1980
			SetScrollInfo(hwnd, scroll, &info, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1981
			break;
1982
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1983
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1984

Alexandre Julliard's avatar
Alexandre Julliard committed
1985

Alexandre Julliard's avatar
Alexandre Julliard committed
1986
/***********************************************************************
1987
 *		ScrollChildren (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
1988
 */
1989
void WINAPI ScrollChildren(HWND hWnd, UINT uMsg, WPARAM wParam,
Alexandre Julliard's avatar
Alexandre Julliard committed
1990
                             LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1991
{
1992 1993
    INT newPos = -1;
    INT curPos, length, minPos, maxPos, shift;
1994
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
1995

1996
    GetClientRect( hWnd, &rect );
Alexandre Julliard's avatar
Alexandre Julliard committed
1997

1998
    switch(uMsg)
Alexandre Julliard's avatar
Alexandre Julliard committed
1999
    {
2000
    case WM_HSCROLL:
2001 2002
	GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
	curPos = GetScrollPos(hWnd,SB_HORZ);
2003
	length = (rect.right - rect.left) / 2;
2004
	shift = GetSystemMetrics(SM_CYHSCROLL);
2005 2006
        break;
    case WM_VSCROLL:
2007 2008
	GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
	curPos = GetScrollPos(hWnd,SB_VERT);
2009
	length = (rect.bottom - rect.top) / 2;
2010
	shift = GetSystemMetrics(SM_CXVSCROLL);
2011 2012
        break;
    default:
2013 2014
        return;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2015

Alexandre Julliard's avatar
Alexandre Julliard committed
2016 2017
    switch( wParam )
    {
2018
	case SB_LINEUP:
Alexandre Julliard's avatar
Alexandre Julliard committed
2019 2020
		        newPos = curPos - shift;
			break;
2021
	case SB_LINEDOWN:
Alexandre Julliard's avatar
Alexandre Julliard committed
2022 2023
			newPos = curPos + shift;
			break;
2024
	case SB_PAGEUP:
Alexandre Julliard's avatar
Alexandre Julliard committed
2025 2026
			newPos = curPos - length;
			break;
2027
	case SB_PAGEDOWN:
Alexandre Julliard's avatar
Alexandre Julliard committed
2028 2029 2030
			newPos = curPos + length;
			break;

2031
	case SB_THUMBPOSITION:
Alexandre Julliard's avatar
Alexandre Julliard committed
2032 2033 2034
			newPos = LOWORD(lParam);
			break;

2035
	case SB_THUMBTRACK:
Alexandre Julliard's avatar
Alexandre Julliard committed
2036 2037
			return;

2038
	case SB_TOP:
Alexandre Julliard's avatar
Alexandre Julliard committed
2039 2040
			newPos = minPos;
			break;
2041
	case SB_BOTTOM:
Alexandre Julliard's avatar
Alexandre Julliard committed
2042 2043 2044
			newPos = maxPos;
			break;
	case SB_ENDSCROLL:
2045
			CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
Alexandre Julliard's avatar
Alexandre Julliard committed
2046
			return;
Alexandre Julliard's avatar
Alexandre Julliard committed
2047
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
2048

Alexandre Julliard's avatar
Alexandre Julliard committed
2049 2050
    if( newPos > maxPos )
	newPos = maxPos;
2051
    else
Alexandre Julliard's avatar
Alexandre Julliard committed
2052 2053
	if( newPos < minPos )
	    newPos = minPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
2054

2055
    SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
2056

Alexandre Julliard's avatar
Alexandre Julliard committed
2057
    if( uMsg == WM_VSCROLL )
2058
	ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
Alexandre Julliard's avatar
Alexandre Julliard committed
2059
			SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliard's avatar
Alexandre Julliard committed
2060
    else
2061
	ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
Alexandre Julliard's avatar
Alexandre Julliard committed
2062
			SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliard's avatar
Alexandre Julliard committed
2063 2064
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2065 2066

/******************************************************************************
2067
 *		CascadeWindows (USER32.@) Cascades MDI child windows
Alexandre Julliard's avatar
Alexandre Julliard committed
2068 2069 2070 2071 2072 2073
 *
 * RETURNS
 *    Success: Number of cascaded windows.
 *    Failure: 0
 */
WORD WINAPI
2074 2075
CascadeWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
		UINT cKids, const HWND *lpKids)
Alexandre Julliard's avatar
Alexandre Julliard committed
2076
{
2077
    FIXME("(%p,0x%08x,...,%u,...): stub\n", hwndParent, wFlags, cKids);
Alexandre Julliard's avatar
Alexandre Julliard committed
2078 2079 2080 2081 2082
    return 0;
}


/******************************************************************************
2083
 *		TileWindows (USER32.@) Tiles MDI child windows
Alexandre Julliard's avatar
Alexandre Julliard committed
2084 2085 2086 2087 2088 2089
 *
 * RETURNS
 *    Success: Number of tiled windows.
 *    Failure: 0
 */
WORD WINAPI
2090 2091
TileWindows (HWND hwndParent, UINT wFlags, const LPRECT lpRect,
	     UINT cKids, const HWND *lpKids)
Alexandre Julliard's avatar
Alexandre Julliard committed
2092
{
2093
    FIXME("(%p,0x%08x,...,%u,...): stub\n", hwndParent, wFlags, cKids);
Alexandre Julliard's avatar
Alexandre Julliard committed
2094 2095 2096
    return 0;
}

2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109
/************************************************************************
 *              "More Windows..." functionality
 */

/*              MDI_MoreWindowsDlgProc
 *
 *    This function will process the messages sent to the "More Windows..."
 *    dialog.
 *    Return values:  0    = cancel pressed
 *                    HWND = ok pressed or double-click in the list...
 *
 */

2110
static INT_PTR WINAPI MDI_MoreWindowsDlgProc (HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
2111 2112 2113 2114 2115 2116 2117 2118
{
    switch (iMsg)
    {
       case WM_INITDIALOG:
       {
           UINT widest       = 0;
           UINT length;
           UINT i;
2119
           MDICLIENTINFO *ci = get_client_info( (HWND)lParam );
2120
           HWND hListBox = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2121
           HWND *list, *sorted_list;
2122

2123
           if (!(list = WIN_ListChildren( (HWND)lParam ))) return TRUE;
2124 2125
           if (!(sorted_list = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                          sizeof(HWND) * ci->nActiveChildren )))
2126
           {
2127
               HeapFree( GetProcessHeap(), 0, list );
2128 2129
               return FALSE;
           }
2130

2131 2132 2133 2134 2135 2136
           /* Fill the list, sorted by id... */
           for (i = 0; list[i]; i++)
           {
               UINT id = GetWindowLongW( list[i], GWL_ID ) - ci->idFirstChild;
               if (id < ci->nActiveChildren) sorted_list[id] = list[i];
           }
2137
           HeapFree( GetProcessHeap(), 0, list );
2138

2139 2140 2141
           for (i = 0; i < ci->nActiveChildren; i++)
           {
               WCHAR buffer[128];
2142

2143 2144 2145 2146 2147
               if (!GetWindowTextW( sorted_list[i], buffer, sizeof(buffer)/sizeof(WCHAR) ))
                   continue;
               SendMessageW(hListBox, LB_ADDSTRING, 0, (LPARAM)buffer );
               SendMessageW(hListBox, LB_SETITEMDATA, i, (LPARAM)sorted_list[i] );
               length = strlenW(buffer);  /* FIXME: should use GetTextExtentPoint */
2148 2149 2150 2151
               if (length > widest)
                   widest = length;
           }
           /* Make sure the horizontal scrollbar scrolls ok */
2152
           SendMessageW(hListBox, LB_SETHORIZONTALEXTENT, widest * 6, 0);
2153 2154

           /* Set the current selection */
2155
           SendMessageW(hListBox, LB_SETCURSEL, MDI_MOREWINDOWSLIMIT, 0);
2156 2157 2158 2159 2160 2161
           return TRUE;
       }

       case WM_COMMAND:
           switch (LOWORD(wParam))
           {
2162 2163 2164
                default:
                    if (HIWORD(wParam) != LBN_DBLCLK) break;
                    /* fall through */
2165 2166 2167 2168 2169 2170
                case IDOK:
                {
                    /*  windows are sorted by menu ID, so we must return the
                     *  window associated to the given id
                     */
                    HWND hListBox     = GetDlgItem(hDlg, MDI_IDC_LISTBOX);
2171
                    UINT index        = SendMessageW(hListBox, LB_GETCURSEL, 0, 0);
2172 2173
                    LRESULT res = SendMessageW(hListBox, LB_GETITEMDATA, index, 0);
                    EndDialog(hDlg, res);
2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195
                    return TRUE;
                }
                case IDCANCEL:
                    EndDialog(hDlg, 0);
                    return TRUE;
           }
           break;
    }
    return FALSE;
}

/*
 *
 *                      MDI_MoreWindowsDialog
 *
 *     Prompts the user with a listbox containing the opened
 *     documents. The user can then choose a windows and click
 *     on OK to set the current window to the one selected, or
 *     CANCEL to cancel. The function returns a handle to the
 *     selected window.
 */

2196
static HWND MDI_MoreWindowsDialog(HWND hwnd)
2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218
{
    LPCVOID template;
    HRSRC hRes;
    HANDLE hDlgTmpl;

    hRes = FindResourceA(GetModuleHandleA("USER32"), "MDI_MOREWINDOWS", RT_DIALOGA);

    if (hRes == 0)
        return 0;

    hDlgTmpl = LoadResource(GetModuleHandleA("USER32"), hRes );

    if (hDlgTmpl == 0)
        return 0;

    template = LockResource( hDlgTmpl );

    if (template == 0)
        return 0;

    return (HWND) DialogBoxIndirectParamA(GetModuleHandleA("USER32"),
                                          (LPDLGTEMPLATEA) template,
2219
                                          hwnd, MDI_MoreWindowsDlgProc, (LPARAM) hwnd);
2220 2221 2222 2223 2224 2225 2226 2227
}

/*
 *
 *                      MDI_SwapMenuItems
 *
 *      Will swap the menu IDs for the given 2 positions.
 *      pos1 and pos2 are menu IDs
2228 2229
 *
 *
2230 2231
 */

2232
static void MDI_SwapMenuItems(HWND parent, UINT pos1, UINT pos2)
2233
{
2234 2235
    HWND *list;
    int i;
2236

2237
    if (!(list = WIN_ListChildren( parent ))) return;
2238
    for (i = 0; list[i]; i++)
2239
    {
2240 2241 2242
        UINT id = GetWindowLongW( list[i], GWL_ID );
        if (id == pos1) SetWindowLongW( list[i], GWL_ID, pos2 );
        else if (id == pos2) SetWindowLongW( list[i], GWL_ID, pos1 );
2243
    }
2244
    HeapFree( GetProcessHeap(), 0, list );
2245
}