source: trunk/src/user32/new/win32wmdiclient.cpp@ 2292

Last change on this file since 2292 was 2292, checked in by cbratschi, 26 years ago

* empty log message *

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