source: trunk/src/user32/win32wmdiclient.cpp@ 3603

Last change on this file since 3603 was 3603, checked in by sandervl, 25 years ago

experimental WM_NCHITTEST generation (disabled) + MDI fixes

File size: 37.9 KB
Line 
1/* $Id: win32wmdiclient.cpp,v 1.27 2000-05-24 19:30:08 sandervl Exp $ */
2/*
3 * Win32 MDI Client Window Class for OS/2
4 *
5 * Copyright 1998-1999 Sander van Leeuwen (sandervl@xs4all.nl)
6 * Copyright 1999 Daniela Engert (dani@ngrt.de)
7 *
8 * Parts based on Corel WINE (window\mdi.c: 20000317)
9 * (Parts based on Wine (windows\mdi.c) (990815))
10 *
11 * Copyright 1994, Bob Amstadt
12 * 1995,1996 Alex Korobka
13 *
14 * Project Odin Software License can be found in LICENSE.TXT
15 *
16 */
17#include <os2win.h>
18#include <win.h>
19#include <stdlib.h>
20#include <math.h>
21#include <string.h>
22#include <stdarg.h>
23#include <assert.h>
24#include <misc.h>
25#include <heapstring.h>
26#include <win32wnd.h>
27#include <win32wmdiclient.h>
28#include <spy.h>
29#include "wndmsg.h"
30#include <oslibwin.h>
31#include <oslibutil.h>
32#include <oslibgdi.h>
33#include <oslibres.h>
34#include "oslibdos.h"
35#include <winres.h>
36#include "syscolor.h"
37#include "win32wndhandle.h"
38
39#define DBG_LOCALLOG DBG_win32wmdiclient
40#include "dbglocal.h"
41
42
43//******************************************************************************
44//******************************************************************************
45Win32MDIClientWindow::Win32MDIClientWindow(CREATESTRUCTA *lpCreateStructA, ATOM classAtom, BOOL isUnicode)
46 : maximizedChild(0), activeChild(0), nActiveChildren(0), nTotalCreated(0),
47 frameTitle(NULL), mdiFlags(0), idFirstChild(0), hWindowMenu(0),
48 sbRecalc(0),
49 Win32BaseWindow(OBJTYPE_WINDOW)
50{
51 Init();
52 this->isUnicode = isUnicode;
53 CreateWindowExA(lpCreateStructA, classAtom);
54}
55//******************************************************************************
56//******************************************************************************
57Win32MDIClientWindow::~Win32MDIClientWindow()
58{
59 if(frameTitle)
60 HeapFree(GetProcessHeap(), 0, frameTitle);
61}
62//******************************************************************************
63//******************************************************************************
64BOOL Win32MDIClientWindow::isMDIClient()
65{
66 return TRUE;
67}
68//******************************************************************************
69//******************************************************************************
70LRESULT Win32MDIClientWindow::MDIClientWndProc(UINT message, WPARAM wParam, LPARAM lParam)
71{
72 LPCREATESTRUCTA cs;
73 LPCLIENTCREATESTRUCT ccs;
74 RECT rect;
75 INT nItems;
76 LRESULT retvalue;
77 Win32Window *frameWnd;
78 Win32MDIChildWindow *mdichild;
79
80 frameWnd = (Win32Window *)getParent();
81 if(frameWnd == NULL) {
82 return 0;
83 }
84
85 switch (message)
86 {
87 case WM_CREATE:
88 cs = (LPCREATESTRUCTA)lParam;
89 ccs = (LPCLIENTCREATESTRUCT)cs->lpCreateParams;
90
91 hWindowMenu = ccs->hWindowMenu;
92 idFirstChild = ccs->idFirstChild;
93
94 maximizedChild = 0;
95 activeChild = 0;
96 nActiveChildren = 0;
97 nTotalCreated = 0;
98 frameTitle = NULL;
99 mdiFlags = 0;
100
101 setStyle(getStyle() | WS_CLIPCHILDREN);
102
103 updateFrameText(MDI_NOFRAMEREPAINT, getParent()->getWindowNameA());
104
105 AppendMenuA( hWindowMenu, MF_SEPARATOR, 0, NULL );
106
107 setClientRect(frameWnd->getClientRectPtr());
108
109 dprintf(("MDIClient created - hwnd = %04x, idFirst = %u\n", getWindowHandle(), idFirstChild ));
110
111 retvalue = 0;
112 goto END;
113
114 case WM_DESTROY:
115 if( maximizedChild ) restoreFrameMenu(getParent());
116
117 if((nItems = GetMenuItemCount(hWindowMenu)) > 0)
118 {
119 idFirstChild = nItems - 1;
120 nActiveChildren++; /* to delete a separator */
121 while( nActiveChildren-- )
122 DeleteMenu(hWindowMenu,MF_BYPOSITION,idFirstChild--);
123 }
124 retvalue = 0;
125 goto END;
126
127 case WM_MDIACTIVATE:
128 if( activeChild && activeChild->getWindowHandle() != (HWND)wParam )
129 {
130 mdichild = (Win32MDIChildWindow *)GetWindowFromHandle((HWND)wParam);
131 if(mdichild) {
132 mdichild->SetWindowPos(0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
133 }
134 }
135 retvalue = 0;
136 goto END;
137
138 case WM_MDICASCADE:
139 retvalue = cascade(wParam);
140 goto END;
141
142 case WM_MDICREATE:
143 if (lParam) {
144 retvalue = Win32MDIChildWindow::createChild( this, (MDICREATESTRUCTA*)lParam );
145 }
146 else retvalue = 0;
147 goto END;
148
149 case WM_MDIDESTROY:
150 mdichild = (Win32MDIChildWindow *)GetWindowFromHandle((HWND)wParam);
151 if(mdichild) {
152 retvalue = destroyChild(mdichild, TRUE );
153 }
154 goto END;
155
156 case WM_MDIGETACTIVE:
157 dprintf(("WM_MDIGETACTIVE: %x %x", this, (activeChild) ? activeChild->getWindowHandle() : 0));
158 if (lParam)
159 *(BOOL *)lParam = (maximizedChild != 0);
160
161 retvalue = (activeChild) ? activeChild->getWindowHandle() : 0;
162 goto END;
163
164 case WM_MDIICONARRANGE:
165 mdiFlags |= MDIF_NEEDUPDATE;
166 ArrangeIconicWindows(Win32Hwnd);
167 sbRecalc = SB_BOTH+1;
168 SendMessageA(WM_MDICALCCHILDSCROLL,0,0L);
169 retvalue = 0;
170 goto END;
171
172 case WM_MDIMAXIMIZE:
173 ::ShowWindow( (HWND)wParam, SW_MAXIMIZE );
174 retvalue = 0;
175 goto END;
176
177 case WM_MDINEXT: /* lParam != 0 means previous window */
178 mdichild = (Win32MDIChildWindow *)GetWindowFromHandle((HWND)wParam);
179 if(mdichild) {
180 switchActiveChild(mdichild, (lParam)? FALSE : TRUE );
181 }
182 break;
183
184 case WM_MDIRESTORE:
185 ::SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
186 retvalue = 0;
187 goto END;
188 case WM_MDISETMENU:
189 retvalue = setMDIMenu((HMENU)wParam, (HMENU)lParam );
190 goto END;
191
192 case WM_MDIREFRESHMENU:
193 retvalue = refreshMDIMenu((HMENU)wParam, (HMENU)lParam );
194 goto END;
195
196 case WM_MDITILE:
197 mdiFlags |= MDIF_NEEDUPDATE;
198 ShowScrollBar(Win32Hwnd,SB_BOTH,FALSE);
199 tile(wParam);
200 mdiFlags &= ~MDIF_NEEDUPDATE;
201 retvalue = 0;
202 goto END;
203
204 case WM_VSCROLL:
205 case WM_HSCROLL:
206 mdiFlags |= MDIF_NEEDUPDATE;
207 ScrollChildren(Win32Hwnd, message, wParam, lParam);
208 mdiFlags &= ~MDIF_NEEDUPDATE;
209 retvalue = 0;
210 goto END;
211
212 case WM_SETFOCUS:
213 if( activeChild )
214 {
215 if( !(activeChild->getStyle() & WS_MINIMIZE) )
216 ::SetFocus(activeChild->getWindowHandle());
217 }
218 retvalue = 0;
219 goto END;
220
221 case WM_NCACTIVATE:
222 if( activeChild )
223 activeChild->SendInternalMessageA(message, wParam, lParam);
224 break;
225
226 case WM_PARENTNOTIFY:
227 if (LOWORD(wParam) == WM_LBUTTONDOWN)
228 {
229 POINTS pt = MAKEPOINTS(lParam);
230 POINT point;
231
232 point.x = pt.x;
233 point.y = pt.y;
234
235 HWND child = ChildWindowFromPoint(getWindowHandle(), point);
236
237 if( child && child != getWindowHandle() && (!activeChild || activeChild->getWindowHandle() != child) )
238 ::SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
239 }
240 retvalue = 0;
241 goto END;
242
243 case WM_SIZE:
244 if( maximizedChild && maximizedChild->IsWindow() )
245 {
246 RECT rect;
247
248 rect.left = 0;
249 rect.top = 0;
250 rect.right = LOWORD(lParam);
251 rect.bottom = HIWORD(lParam);
252
253 AdjustWindowRectEx(&rect, maximizedChild->getStyle(), 0, maximizedChild->getExStyle());
254 ::MoveWindow(maximizedChild->getWindowHandle(), rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 1);
255 }
256 else postUpdate(SB_BOTH+1);
257 break;
258
259 case WM_MDICALCCHILDSCROLL:
260 if( (mdiFlags & MDIF_NEEDUPDATE) && sbRecalc )
261 {
262 CalcChildScroll(Win32Hwnd, sbRecalc-1);
263 sbRecalc = 0;
264 mdiFlags &= ~MDIF_NEEDUPDATE;
265 }
266 retvalue = 0;
267 goto END;
268 }
269 retvalue = DefWindowProcA(message, wParam, lParam );
270END:
271 return retvalue;
272}
273/**********************************************************************
274 * MDIClientWndProc
275 *
276 * This function handles all MDI requests.
277 */
278LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
279 LPARAM lParam )
280{
281 Win32MDIClientWindow *window;
282
283 window = (Win32MDIClientWindow *)Win32BaseWindow::GetWindowFromHandle(hwnd);
284 if(!window) {
285 dprintf(("MDIClientWndProc, window %x not found", hwnd));
286 return 0;
287 }
288 return window->MDIClientWndProc(message, wParam, lParam);
289}
290/**********************************************************************
291 * MDI_GetWindow
292 *
293 * returns "activateable" child different from the current or zero
294 */
295Win32MDIChildWindow *Win32MDIClientWindow::getWindow(Win32MDIChildWindow *actchild, BOOL bNext,
296 DWORD dwStyleMask)
297{
298 Win32MDIChildWindow *lastchild = 0, *curchild;
299
300 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
301
302 if( !actchild ) actchild = getActiveChild();
303 if( !actchild) return 0;
304
305 for ( curchild = (Win32MDIChildWindow *)actchild->getNextChild(); ; curchild = (Win32MDIChildWindow *)curchild->getNextChild())
306 {
307 if (!curchild ) curchild = (Win32MDIChildWindow *)getFirstChild();
308
309 if ( curchild == actchild ) break; /* went full circle */
310
311 if (!curchild->getOwner() && (curchild->getStyle() & dwStyleMask) == WS_VISIBLE )
312 {
313 lastchild = curchild;
314 if ( bNext ) break;
315 }
316 }
317 return lastchild;
318}
319/**********************************************************************
320 * MDI_ChildActivate
321 *
322 * Note: hWndChild is NULL when last child is being destroyed
323 */
324LONG Win32MDIClientWindow::childActivate(Win32MDIChildWindow *child)
325{
326 BOOL isActiveFrameWnd = 0;
327 LONG retvalue;
328 Win32MDIChildWindow *prevActive = activeChild;
329
330 if( child && child->getStyle() & WS_DISABLED )
331 {
332 return 0;
333 }
334
335 /* Don't activate if it is already active. Might happen
336 since ShowWindow DOES activate MDI children */
337 if(activeChild == child)
338 {
339 return 0;
340 }
341
342 if( GetActiveWindow() == getParent()->getWindowHandle())
343 isActiveFrameWnd = TRUE;
344
345 /* deactivate prev. active child */
346 if( prevActive )
347 {
348 prevActive->setStyle(prevActive->getStyle() | WS_SYSMENU);
349 prevActive->SendInternalMessageA( WM_NCACTIVATE, FALSE, 0L );
350 prevActive->SendInternalMessageA( WM_MDIACTIVATE, (WPARAM)prevActive->getWindowHandle(), (LPARAM)(child) ? child->getWindowHandle() : 0);
351
352 /* uncheck menu item */
353 if( getMDIMenu() )
354 CheckMenuItem(getMDIMenu(), prevActive->getWindowId(), 0);
355 }
356
357 /* set appearance */
358 if( maximizedChild)
359 {
360 if( maximizedChild != child) {
361 if( child ) {
362 activeChild = child;
363 child->ShowWindow(SW_SHOWMAXIMIZED);
364 }
365 else
366 if(activeChild) activeChild->ShowWindow( SW_SHOWNORMAL );
367 }
368 }
369
370 dprintf(("childActivate: %x %x", this, (child) ? child->getWindowHandle() : 0));
371 activeChild = child;
372
373 /* check if we have any children left */
374 if( !activeChild )
375 {
376 if( isActiveFrameWnd )
377 SetFocus(getWindowHandle());
378
379 return 0;
380 }
381
382 /* check menu item */
383 if( getMDIMenu() )
384 CheckMenuItem(getMDIMenu(), child->getWindowId(), MF_CHECKED);
385
386 /* bring active child to the top */
387 child->SetWindowPos( 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
388
389 if( isActiveFrameWnd )
390 {
391 child->SendInternalMessageA( WM_NCACTIVATE, TRUE, 0L);
392 if( GetFocus() == getWindowHandle())
393 SendInternalMessageA( WM_SETFOCUS, (WPARAM)getWindowHandle(), 0L );
394 else
395 SetFocus( getWindowHandle() );
396 }
397
398 /* @@@PH prevActive may be NULL actually ?! */
399 child->SendInternalMessageA( WM_MDIACTIVATE,
400 prevActive ? (WPARAM)prevActive->getWindowHandle() : 0,
401 child->getWindowHandle());
402 return TRUE;
403}
404/**********************************************************************
405 * MDI_SwitchActiveChild
406 *
407 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
408 * being activated
409 */
410void Win32MDIClientWindow::switchActiveChild(Win32MDIChildWindow *nextActiveChild, BOOL bNextWindow )
411{
412 Win32MDIChildWindow *prevActiveChild = 0;
413
414 if ( !nextActiveChild) return; /* no window to switch to */
415
416 prevActiveChild = getActiveChild();
417
418 if ( prevActiveChild != nextActiveChild)
419 {
420 BOOL bOptimize = 0;
421
422 if( getMaximizedChild() )
423 {
424 bOptimize = 1;
425 nextActiveChild->setStyle(nextActiveChild->getStyle()& ~WS_VISIBLE);
426 }
427
428 nextActiveChild->SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
429
430 if( bNextWindow && prevActiveChild )
431 prevActiveChild->SetWindowPos(HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
432
433 if( bOptimize )
434 ShowWindow(SW_SHOW );
435 }
436}
437
438
439/**********************************************************************
440 * MDIDestroyChild
441 */
442LRESULT Win32MDIClientWindow::destroyChild(Win32MDIChildWindow *child, BOOL flagDestroy )
443{
444 if( child == getActiveChild())
445 {
446 switchActiveChild(child, TRUE);
447
448 if( child == getActiveChild() )
449 {
450 ::ShowWindow(child->getWindowHandle(),SW_HIDE);
451 if( child == getMaximizedChild() )
452 {
453 restoreFrameMenu(child);
454 setMaximizedChild(NULL);
455 updateFrameText(TRUE,NULL);
456 }
457 childActivate(0);
458 }
459 }
460 child->menuDeleteItem();
461
462 decNrActiveChildren();
463
464 dprintf(("child destroyed - %04x\n", child->getWindowHandle()));
465
466 if (flagDestroy)
467 {
468 postUpdate(SB_BOTH+1);
469 ::DestroyWindow(child->getWindowHandle());
470 }
471
472 return 0;
473}
474/**********************************************************************
475 * MDI_UpdateFrameText
476 *
477 * used when child window is maximized/restored
478 *
479 * Note: lpTitle can be NULL
480 */
481void Win32MDIClientWindow::updateFrameText(BOOL repaint, LPCSTR lpTitle )
482{
483 char lpBuffer[MDI_MAXTITLELENGTH+1];
484
485 /* store new "default" title if lpTitle is not NULL */
486 if (lpTitle)
487 {
488 if (frameTitle) HeapFree( GetProcessHeap(), 0, frameTitle );
489 frameTitle = HEAP_strdupA( GetProcessHeap(), 0, lpTitle );
490 }
491
492 if (frameTitle)
493 {
494 Win32MDIChildWindow *childWnd = getMaximizedChild();
495
496 if( childWnd && childWnd->getWindowNameA() )
497 {
498 /* combine frame title and child title if possible */
499
500 LPCSTR lpBracket = " - [";
501 int i_frame_text_length = strlen(frameTitle);
502 int i_child_text_length = strlen(childWnd->getWindowNameA());
503
504 lstrcpynA( lpBuffer, frameTitle, MDI_MAXTITLELENGTH);
505
506 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
507 {
508 strcat( lpBuffer, lpBracket );
509
510 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
511 {
512 strcat( lpBuffer, childWnd->getWindowNameA());
513 strcat( lpBuffer, "]" );
514 }
515 else
516 {
517 lstrcpynA(lpBuffer + i_frame_text_length + 4,
518 childWnd->getWindowNameA(), MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
519 strcat( lpBuffer, "]" );
520 }
521 }
522 }
523 else
524 {
525 lstrcpynA(lpBuffer, frameTitle, MDI_MAXTITLELENGTH );
526 lpBuffer[MDI_MAXTITLELENGTH]='\0';
527 }
528 }
529 else
530 lpBuffer[0] = '\0';
531
532 getParent()->SetWindowTextA(lpBuffer);
533 if( repaint == MDI_REPAINTFRAME)
534 getParent()->SetWindowPos(0,0,0,0,0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
535}
536/**********************************************************************
537 * MDISetMenu
538 */
539LRESULT Win32MDIClientWindow::setMDIMenu(HMENU hmenuFrame, HMENU hmenuWindow)
540{
541 HWND hwndFrame = ::GetParent(getWindowHandle());
542 HMENU oldFrameMenu = ::GetMenu(hwndFrame);
543
544 if( maximizedChild && hmenuFrame && hmenuFrame!=oldFrameMenu )
545 restoreFrameMenu(maximizedChild);
546
547 if( hmenuWindow && hmenuWindow != hWindowMenu )
548 {
549 /* delete menu items from ci->hWindowMenu
550 * and add them to hmenuWindow */
551
552 INT i = GetMenuItemCount(hWindowMenu) - 1;
553 INT pos = GetMenuItemCount(hmenuWindow) + 1;
554
555 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
556
557 if( nActiveChildren )
558 {
559 INT j = i - nActiveChildren + 1;
560 char buffer[100];
561 UINT id,state;
562
563 for( ; i >= j ; i-- )
564 {
565 id = GetMenuItemID(hWindowMenu,i );
566 state = GetMenuState(hWindowMenu,i,MF_BYPOSITION);
567
568 GetMenuStringA(hWindowMenu, i, buffer, 100, MF_BYPOSITION);
569
570 DeleteMenu(hWindowMenu, i , MF_BYPOSITION);
571 InsertMenuA(hmenuWindow, pos, MF_BYPOSITION | MF_STRING,
572 id, buffer);
573 CheckMenuItem(hmenuWindow ,pos , MF_BYPOSITION | (state & MF_CHECKED));
574 }
575 }
576
577 /* remove separator */
578 DeleteMenu(hWindowMenu, i, MF_BYPOSITION);
579
580 hWindowMenu = hmenuWindow;
581 }
582
583 if( hmenuFrame && hmenuFrame!=oldFrameMenu)
584 {
585 ::SetMenu(hwndFrame, hmenuFrame);
586
587 if (maximizedChild)
588 augmentFrameMenu(maximizedChild);
589
590 return oldFrameMenu;
591 }
592 return 0;
593}
594
595/**********************************************************************
596 * MDIRefreshMenu
597 */
598LRESULT Win32MDIClientWindow::refreshMDIMenu(HMENU hmenuFrame, HMENU hmenuWindow)
599{
600 HMENU oldFrameMenu = getParent()->GetMenu();
601
602// FIXME("partially function stub\n");
603
604 return oldFrameMenu;
605}
606/**********************************************************************
607 * MDI_RestoreFrameMenu
608 */
609BOOL Win32MDIClientWindow::restoreFrameMenu(Win32BaseWindow *child)
610{
611 MENUITEMINFOA menuInfo;
612 INT nItems = GetMenuItemCount(getParent()->GetMenu()) - 1;
613 UINT iId = GetMenuItemID(getParent()->GetMenu(),nItems) ;
614
615 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
616 return 0;
617
618 /*
619 * Remove the system menu, If that menu is the icon of the window
620 * as it is in win95, we have to delete the bitmap.
621 */
622 menuInfo.cbSize = sizeof(MENUITEMINFOA);
623 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
624
625 GetMenuItemInfoA(getParent()->GetMenu(),
626 0,
627 TRUE,
628 &menuInfo);
629
630 RemoveMenu(getParent()->GetMenu(),0,MF_BYPOSITION);
631
632//TODO: See augmentframemenu
633#if 0
634 if ((menuInfo.fType & MFT_BITMAP) &&
635 (LOWORD(menuInfo.dwTypeData)!=0) &&
636 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
637 {
638 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
639 }
640#endif
641
642 /* close */
643 DeleteMenu(getParent()->GetMenu(),GetMenuItemCount(getParent()->GetMenu()) - 1,MF_BYPOSITION);
644
645 /* restore */
646 DeleteMenu(getParent()->GetMenu(),GetMenuItemCount(getParent()->GetMenu()) - 1,MF_BYPOSITION);
647 /* minimize */
648 DeleteMenu(getParent()->GetMenu(),GetMenuItemCount(getParent()->GetMenu()) - 1,MF_BYPOSITION);
649
650 DrawMenuBar(getParent()->getWindowHandle());
651
652 return 1;
653}
654
655Win32BaseWindow** Win32MDIClientWindow::buildWindowArray(UINT bwaFlags,PUINT total)
656{
657 Win32BaseWindow **list = NULL,*win32wnd,**pos;
658 UINT skipHidden;
659 DWORD skipFlags;
660
661 skipHidden = bwaFlags & BWA_SKIPHIDDEN;
662 skipFlags = (bwaFlags & BWA_SKIPDISABLED) ? WS_DISABLED : 0;
663 if (bwaFlags & BWA_SKIPICONIC) skipFlags |= WS_MINIMIZE;
664
665 /* First count the windows */
666 *total = 0;
667 win32wnd = (Win32BaseWindow*)this->getFirstChild();
668 while (win32wnd)
669 {
670 if (!(win32wnd->getStyle() & skipFlags) && (!skipHidden || (win32wnd->getStyle() & WS_VISIBLE)))
671 (*total)++;
672 win32wnd = (Win32BaseWindow*)win32wnd->getNextChild();
673 }
674
675 if (*total)
676 {
677 /* Now build the list of all windows */
678 list = (Win32BaseWindow**)HeapAlloc(GetProcessHeap(),0,sizeof(Win32BaseWindow*)*(*total+1));
679 if (list)
680 {
681 for (win32wnd = (Win32BaseWindow*)this->getFirstChild(),pos = list;win32wnd;win32wnd = (Win32BaseWindow*)win32wnd->getNextChild())
682 {
683 if ((win32wnd->getStyle() & skipFlags));
684 else if(!skipHidden || win32wnd->getStyle() & WS_VISIBLE)
685 *pos++ = win32wnd;
686 }
687 *pos = NULL;
688 }
689 }
690
691 return list;
692}
693
694void Win32MDIClientWindow::releaseWindowArray(Win32BaseWindow **wndArray)
695{
696 HeapFree(GetProcessHeap(),0,wndArray);
697}
698
699/**********************************************************************
700 * MDI_CalcDefaultChildPos
701 *
702 * It seems that the default height is about 2/3 of the client rect
703 */
704void Win32MDIClientWindow::calcDefaultChildPos(WORD n,LPPOINT lpPos,INT delta)
705{
706 INT nstagger;
707 RECT rect;
708 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
709 GetSystemMetrics(SM_CYFRAME) - 1;
710
711 getClientRect(&rect);
712 if( rect.bottom - rect.top - delta >= spacing )
713 rect.bottom -= delta;
714
715 nstagger = (rect.bottom - rect.top)/(3 * spacing);
716 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
717 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
718 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
719}
720
721/**********************************************************************
722 * MDICascade
723 */
724BOOL Win32MDIClientWindow::cascade(UINT fuCascade)
725{
726 Win32BaseWindow **list;
727 UINT total = 0;
728
729 if (getMaximizedChild())
730 SendInternalMessageA(WM_MDIRESTORE, (WPARAM)getMaximizedChild()->getWindowHandle(), 0);
731
732 if (nActiveChildren == 0) return 0;
733
734 list = buildWindowArray(BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC,&total);
735 if (list)
736 {
737 Win32BaseWindow** heapPtr = list;
738 if (total)
739 {
740 INT delta = 0,n = 0;
741 POINT pos[2];
742
743
744 if (total < nActiveChildren)
745 delta = GetSystemMetrics(SM_CYICONSPACING)+GetSystemMetrics(SM_CYICON);
746
747 // walk the list (backwards) and move windows
748 while (*list) list++;
749 while (list != heapPtr)
750 {
751 list--;
752
753 calcDefaultChildPos(n++,pos,delta);
754 ::SetWindowPos((*list)->getWindowHandle(),0,pos[0].x,pos[0].y,pos[1].x,pos[1].y,SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
755 }
756 }
757 releaseWindowArray(heapPtr);
758 }
759
760 if (total < nActiveChildren)
761 ArrangeIconicWindows(Win32Hwnd);
762
763 return TRUE;
764}
765
766/**********************************************************************
767 * MDITile
768 */
769BOOL Win32MDIClientWindow::tile(UINT fuTile)
770{
771 Win32BaseWindow** list;
772 UINT total = 0;
773
774 if (getMaximizedChild())
775 SendInternalMessageA(WM_MDIRESTORE, (WPARAM)getMaximizedChild()->getWindowHandle(), 0);
776
777 if (nActiveChildren == 0) return TRUE;
778
779 list = buildWindowArray(BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
780 ((fuTile & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
781
782 if (list)
783 {
784 Win32BaseWindow** heapPtr = list;
785
786 if (total)
787 {
788 RECT rect;
789 int x, y, xsize, ysize;
790 int rows, columns, r, c, i;
791
792 GetClientRect(Win32Hwnd,&rect);
793 rows = (int) sqrt((double)total);
794 columns = total / rows;
795
796 if( fuTile & MDITILE_HORIZONTAL ) // version >= 3.1
797 {
798 i = rows;
799 rows = columns; // exchange r and c
800 columns = i;
801 }
802
803 if( total != nActiveChildren)
804 {
805 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
806 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
807 }
808
809 ysize = rect.bottom / rows;
810 xsize = rect.right / columns;
811
812 for (x = i = 0, c = 1; c <= columns && *list; c++)
813 {
814 if (c == columns)
815 {
816 rows = total - i;
817 ysize = rect.bottom / rows;
818 }
819
820 y = 0;
821 for (r = 1; r <= rows && *list; r++, i++)
822 {
823 ::SetWindowPos((*list)->getWindowHandle(), 0, x, y, xsize, ysize,
824 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
825 y += ysize;
826 list++;
827 }
828 x += xsize;
829 }
830 }
831 releaseWindowArray(heapPtr);
832 }
833
834 if( total < nActiveChildren ) ArrangeIconicWindows(Win32Hwnd);
835
836 return TRUE;
837}
838
839/* ----------------------- Frame window ---------------------------- */
840
841/**********************************************************************
842 * MDI_AugmentFrameMenu
843 */
844BOOL Win32MDIClientWindow::augmentFrameMenu(Win32MDIChildWindow *child)
845{
846 HMENU hSysPopup = 0,hFrameMenu = ::GetMenu(getParent()->getWindowHandle()),hSysMenu = ::GetSystemMenu(child->getWindowHandle(),FALSE);
847 HBITMAP hSysMenuBitmap = 0;
848
849 if (!hFrameMenu || !hSysMenu)
850 return 0;
851
852 // create a copy of sysmenu popup and insert it into frame menu bar
853
854 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
855 return 0;
856
857 //TRACE("\tgot popup %04x in sysmenu %04x\n",
858 // hSysPopup, child->hSysMenu);
859
860 AppendMenuA(hFrameMenu,MF_HELP | MF_BITMAP,
861 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
862 AppendMenuA(hFrameMenu,MF_HELP | MF_BITMAP,
863 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
864
865 // In Win 95 look, the system menu is replaced by the child icon
866
867 /* Find icon */
868 HICON hIcon = child->IconForWindow(ICON_SMALL);
869
870 if (hIcon)
871 {
872 HDC hMemDC;
873 HBITMAP hBitmap, hOldBitmap;
874 HBRUSH hBrush;
875 HDC hdc = GetDC(child->getWindowHandle());
876
877 if (hdc)
878 {
879 int cx, cy;
880
881 cx = GetSystemMetrics(SM_CXSMICON);
882 cy = GetSystemMetrics(SM_CYSMICON);
883 hMemDC = CreateCompatibleDC(hdc);
884 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
885 hOldBitmap = SelectObject(hMemDC, hBitmap);
886 SetMapMode(hMemDC, MM_TEXT);
887 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
888 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
889 SelectObject (hMemDC, hOldBitmap);
890 DeleteObject(hBrush);
891 DeleteDC(hMemDC);
892 ReleaseDC(child->getWindowHandle(), hdc);
893 hSysMenuBitmap = hBitmap;
894 }
895 }
896
897 if( !InsertMenuA(hFrameMenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
898 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
899 {
900 //TRACE("not inserted\n");
901 DestroyMenu(hSysPopup);
902 return 0;
903 }
904
905 // The close button is only present in Win 95 look
906
907 AppendMenuA(hFrameMenu,MF_HELP | MF_BITMAP,
908 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
909
910 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
911 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
912 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
913 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
914
915 // redraw menu
916 DrawMenuBar(getParent()->getWindowHandle());
917
918 return 1;
919}
920
921/**********************************************************************
922 * MDI_RestoreFrameMenu
923 */
924BOOL Win32MDIClientWindow::restoreFrameMenu(Win32MDIChildWindow *child)
925{
926 MENUITEMINFOA menuInfo;
927 HMENU hFrameMenu = ::GetMenu(getParent()->getWindowHandle());
928 INT nItems = GetMenuItemCount(hFrameMenu) - 1;
929 UINT iId = GetMenuItemID(hFrameMenu,nItems) ;
930
931 //TRACE("frameWnd %p,child %04x\n",frameWnd,hChild);
932
933 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
934 return 0;
935
936 /*
937 * Remove the system menu, If that menu is the icon of the window
938 * as it is in win95, we have to delete the bitmap.
939 */
940
941 menuInfo.cbSize = sizeof(MENUITEMINFOA);
942 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
943
944 GetMenuItemInfoA(hFrameMenu,
945 0,
946 TRUE,
947 &menuInfo);
948
949 RemoveMenu(hFrameMenu,0,MF_BYPOSITION);
950
951#if 0 //CB: hBmpClose not (yet) defined
952 if ( (menuInfo.fType & MFT_BITMAP) &&
953 (LOWORD(menuInfo.dwTypeData)!=0) &&
954 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
955 {
956 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
957 }
958#endif
959
960 // close
961 DeleteMenu(hFrameMenu,GetMenuItemCount(hFrameMenu) - 1,MF_BYPOSITION);
962
963 // restore
964 DeleteMenu(hFrameMenu,GetMenuItemCount(hFrameMenu) - 1,MF_BYPOSITION);
965 // minimize
966 DeleteMenu(hFrameMenu,GetMenuItemCount(hFrameMenu) - 1,MF_BYPOSITION);
967
968 DrawMenuBar(getParent()->getWindowHandle());
969
970 return 1;
971}
972
973/***********************************************************************
974 * CalcChildScroll (USER.462)
975 */
976void WINAPI CalcChildScroll(HWND hwnd,WORD scroll)
977{
978 Win32BaseWindow *win32wnd = Win32BaseWindow::GetWindowFromHandle(hwnd);
979 SCROLLINFO info;
980 RECT childRect, clientRect;
981 INT vmin, vmax, hmin, hmax, vpos, hpos;
982
983 if (!win32wnd) return;
984
985 GetClientRect( hwnd, &clientRect );
986 SetRectEmpty( &childRect );
987
988 for (win32wnd = (Win32BaseWindow*)win32wnd->getFirstChild();win32wnd;win32wnd = (Win32BaseWindow*)win32wnd->getNextChild())
989 {
990 if( win32wnd->getStyle() & WS_MAXIMIZE )
991 {
992 ShowScrollBar(hwnd, SB_BOTH, FALSE);
993 return;
994 }
995 UnionRect(&childRect,win32wnd->getWindowRect(),&childRect);
996 }
997 UnionRect( &childRect, &clientRect, &childRect );
998
999 hmin = childRect.left; hmax = childRect.right - clientRect.right;
1000 hpos = clientRect.left - childRect.left;
1001 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
1002 vpos = clientRect.top - childRect.top;
1003
1004 switch( scroll )
1005 {
1006 case SB_HORZ:
1007 vpos = hpos; vmin = hmin; vmax = hmax;
1008 case SB_VERT:
1009 info.cbSize = sizeof(info);
1010 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
1011 info.fMask = SIF_POS | SIF_RANGE;
1012 SetScrollInfo(hwnd, scroll, &info, TRUE);
1013 break;
1014 case SB_BOTH:
1015 {
1016 SCROLLINFO vInfo, hInfo;
1017
1018 vInfo.cbSize = hInfo.cbSize = sizeof(SCROLLINFO);
1019 vInfo.nMin = vmin;
1020 hInfo.nMin = hmin;
1021 vInfo.nMax = vmax;
1022 hInfo.nMax = hmax;
1023 vInfo.nPos = vpos;
1024 hInfo.nPos = hpos;
1025 vInfo.fMask = hInfo.fMask = SIF_RANGE | SIF_POS;
1026
1027 SetScrollInfo(hwnd,SB_VERT,&vInfo,TRUE);
1028 SetScrollInfo(hwnd,SB_HORZ,&hInfo,TRUE);
1029 }
1030 }
1031}
1032
1033/***********************************************************************
1034 * ScrollChildren32 (USER32.448)
1035 */
1036void WINAPI ScrollChildren(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
1037{
1038 Win32BaseWindow *win32wnd = Win32BaseWindow::GetWindowFromHandle(hWnd);
1039 INT newPos = -1;
1040 INT curPos, length, minPos, maxPos, shift;
1041
1042 if (!win32wnd) return;
1043
1044 if (uMsg == WM_HSCROLL)
1045 {
1046 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
1047 curPos = GetScrollPos(hWnd,SB_HORZ);
1048 length = win32wnd->getClientWidth()/2;
1049 shift = GetSystemMetrics(SM_CYHSCROLL);
1050 } else if (uMsg == WM_VSCROLL)
1051 {
1052 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
1053 curPos = GetScrollPos(hWnd,SB_VERT);
1054 length = win32wnd->getClientHeight()/2;
1055 shift = GetSystemMetrics(SM_CXVSCROLL);
1056 } else return;
1057
1058 switch( wParam )
1059 {
1060 case SB_LINEUP:
1061 newPos = curPos - shift;
1062 break;
1063
1064 case SB_LINEDOWN:
1065 newPos = curPos + shift;
1066 break;
1067
1068 case SB_PAGEUP:
1069 newPos = curPos - length;
1070 break;
1071
1072 case SB_PAGEDOWN:
1073 newPos = curPos + length;
1074 break;
1075
1076 case SB_THUMBPOSITION:
1077 newPos = LOWORD(lParam);
1078 break;
1079
1080 case SB_THUMBTRACK:
1081 return;
1082
1083 case SB_TOP:
1084 newPos = minPos;
1085 break;
1086
1087 case SB_BOTTOM:
1088 newPos = maxPos;
1089 break;
1090
1091 case SB_ENDSCROLL:
1092 CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
1093 return;
1094 }
1095
1096 if( newPos > maxPos )
1097 newPos = maxPos;
1098 else
1099 if( newPos < minPos )
1100 newPos = minPos;
1101
1102 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
1103
1104 if( uMsg == WM_VSCROLL )
1105 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
1106 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1107 else
1108 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
1109 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1110}
1111
1112/*****************************************************************************
1113 * Name : WORD WIN32API CascadeWindows
1114 * Purpose : The CascadeWindows function cascades the specified windows or
1115 * the child windows of the specified parent window.
1116 * Parameters: HWND hwndParent handle of parent window
1117 * UINT wHow types of windows not to arrange
1118 * CONST RECT * lpRect rectangle to arrange windows in
1119 * UINT cKids number of windows to arrange
1120 * const HWND FAR * lpKids array of window handles
1121 * Variables :
1122 * Result : If the function succeeds, the return value is the number of windows arranged.
1123 * If the function fails, the return value is zero.
1124 * Remark :
1125 * Status : UNTESTED STUB
1126 *
1127 * Author : Patrick Haller [Thu, 1998/02/26 11:55]
1128 *****************************************************************************/
1129WORD WIN32API CascadeWindows(HWND hwndParent,
1130 UINT wHow,
1131 CONST LPRECT lpRect,
1132 UINT cKids,
1133 const HWND *lpKids)
1134{
1135 dprintf(("USER32:CascadeWindows(%08xh,%u,%08xh,%u,%08x) not implemented.\n",
1136 hwndParent,
1137 wHow,
1138 lpRect,
1139 cKids,
1140 lpKids));
1141
1142 return (0);
1143}
1144
1145/*****************************************************************************
1146 * Name : BOOL WIN32API CascadeChildWindows
1147 * Purpose : Unknown
1148 * Parameters: Unknown
1149 * Variables :
1150 * Result :
1151 * Remark :
1152 * Status : UNTESTED UNKNOWN STUB
1153 *
1154 * Author : Patrick Haller [Wed, 1998/06/16 11:55]
1155 *****************************************************************************/
1156BOOL WIN32API CascadeChildWindows(DWORD x1,
1157 DWORD x2)
1158{
1159 dprintf(("USER32: CascadeChildWindows(%08xh,%08xh) not implemented.\n",
1160 x1,
1161 x2));
1162
1163 return (FALSE); /* default */
1164}
1165
1166/*****************************************************************************
1167 * Name : WORD WIN32API TileWindows
1168 * Purpose : The TileWindows function tiles the specified windows, or the child
1169 * windows of the specified parent window.
1170 * Parameters: HWND hwndParent handle of parent window
1171 * WORD wFlags types of windows not to arrange
1172 * LPCRECT lpRect rectangle to arrange windows in
1173 * WORD cChildrenb number of windows to arrange
1174 * const HWND *ahwndChildren array of window handles
1175 * Variables :
1176 * Result : If the function succeeds, the return value is the number of
1177 * windows arranged.
1178 * If the function fails, the return value is zero.
1179 * Remark :
1180 * Status : UNTESTED STUB
1181 *
1182 * Author : Patrick Haller [Thu, 1998/02/26 11:55]
1183 *****************************************************************************/
1184WORD WIN32API TileWindows(HWND hwndParent,
1185 UINT wFlags,
1186 const LPRECT lpRect,
1187 UINT cChildrenb,
1188 const HWND *ahwndChildren)
1189{
1190 dprintf(("USER32:TileWindows (%08xh,%08xh,%08xh,%08xh,%08x) not implemented.\n",
1191 hwndParent,
1192 wFlags,
1193 lpRect,
1194 cChildrenb,
1195 ahwndChildren));
1196
1197 return (0);
1198}
1199
1200/*****************************************************************************
1201 * Name : BOOL WIN32API TileChildWindows
1202 * Purpose : Unknown
1203 * Parameters: Unknown
1204 * Variables :
1205 * Result :
1206 * Remark :
1207 * Status : UNTESTED UNKNOWN STUB
1208 *
1209 * Author : Patrick Haller [Wed, 1998/06/16 11:55]
1210 *****************************************************************************/
1211BOOL WIN32API TileChildWindows(DWORD x1,
1212 DWORD x2)
1213{
1214 dprintf(("USER32: TileChildWindows(%08xh,%08xh) not implemented.\n",
1215 x1,
1216 x2));
1217
1218 return (FALSE); /* default */
1219}
1220
1221/* -------- Miscellaneous service functions ----------
1222 *
1223 * MDI_GetChildByID
1224 */
1225Win32MDIChildWindow *Win32MDIClientWindow::getChildByID(INT id)
1226{
1227 Win32MDIChildWindow *child;
1228
1229 for (child = (Win32MDIChildWindow *)getFirstChild() ; child; child = (Win32MDIChildWindow *)child->getNextChild())
1230 if (child->getWindowId() == id) return child;
1231
1232 return 0;
1233}
1234
1235void Win32MDIClientWindow::postUpdate(WORD recalc)
1236{
1237 if( !(mdiFlags & MDIF_NEEDUPDATE) )
1238 {
1239 mdiFlags |= MDIF_NEEDUPDATE;
1240 PostMessageA(getWindowHandle(), WM_MDICALCCHILDSCROLL, 0, 0);
1241 }
1242 sbRecalc = recalc;
1243}
1244//******************************************************************************
1245//******************************************************************************
1246BOOL MDICLIENT_Register()
1247{
1248 WNDCLASSA wndClass;
1249
1250//SvL: Don't check this now
1251// if (GlobalFindAtomA(MDICLIENTCLASSNAMEA)) return FALSE;
1252
1253 ZeroMemory(&wndClass,sizeof(WNDCLASSA));
1254 wndClass.style = CS_GLOBALCLASS;
1255 wndClass.lpfnWndProc = (WNDPROC)MDIClientWndProc;
1256 wndClass.cbClsExtra = 0;
1257 wndClass.cbWndExtra = 0;
1258 wndClass.hCursor = 0;
1259 wndClass.hbrBackground = (HBRUSH)LTGRAY_BRUSH;
1260 wndClass.lpszClassName = MDICLIENTCLASSNAMEA;
1261
1262 return RegisterClassA(&wndClass);
1263}
1264//******************************************************************************
1265//******************************************************************************
1266BOOL MDICLIENT_Unregister()
1267{
1268 if (GlobalFindAtomA(MDICLIENTCLASSNAMEA))
1269 return UnregisterClassA(MDICLIENTCLASSNAMEA,(HINSTANCE)NULL);
1270 else return FALSE;
1271}
1272//******************************************************************************
1273//******************************************************************************
Note: See TracBrowser for help on using the repository browser.