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

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

mdi fix + ShowOwnedPopups implemented

File size: 37.9 KB
Line 
1/* $Id: win32wmdiclient.cpp,v 1.30 2000-10-09 17:26:54 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 "syscolor.h"
36#include "win32wndhandle.h"
37
38#define DBG_LOCALLOG DBG_win32wmdiclient
39#include "dbglocal.h"
40
41
42//******************************************************************************
43//******************************************************************************
44Win32MDIClientWindow::Win32MDIClientWindow(CREATESTRUCTA *lpCreateStructA, ATOM classAtom, BOOL isUnicode)
45 : maximizedChild(0), activeChild(0), nActiveChildren(0), nTotalCreated(0),
46 frameTitle(NULL), mdiFlags(0), idFirstChild(0), hWindowMenu(0),
47 sbRecalc(0),
48 Win32BaseWindow(OBJTYPE_WINDOW)
49{
50 Init();
51 this->isUnicode = isUnicode;
52 CreateWindowExA(lpCreateStructA, classAtom);
53}
54//******************************************************************************
55//******************************************************************************
56Win32MDIClientWindow::~Win32MDIClientWindow()
57{
58 if(frameTitle)
59 HeapFree(GetProcessHeap(), 0, frameTitle);
60}
61//******************************************************************************
62//******************************************************************************
63BOOL Win32MDIClientWindow::isMDIClient()
64{
65 return TRUE;
66}
67//******************************************************************************
68//******************************************************************************
69LRESULT Win32MDIClientWindow::MDIClientWndProc(UINT message, WPARAM wParam, LPARAM lParam)
70{
71 LPCREATESTRUCTA cs;
72 LPCLIENTCREATESTRUCT ccs;
73 RECT rect;
74 INT nItems;
75 LRESULT retvalue;
76 Win32Window *frameWnd;
77 Win32MDIChildWindow *mdichild;
78
79 frameWnd = (Win32Window *)getParent();
80 if(frameWnd == NULL) {
81 return 0;
82 }
83
84 switch (message)
85 {
86 case WM_CREATE:
87 cs = (LPCREATESTRUCTA)lParam;
88 ccs = (LPCLIENTCREATESTRUCT)cs->lpCreateParams;
89
90 hWindowMenu = ccs->hWindowMenu;
91 idFirstChild = ccs->idFirstChild;
92
93 maximizedChild = 0;
94 activeChild = 0;
95 nActiveChildren = 0;
96 nTotalCreated = 0;
97 frameTitle = NULL;
98 mdiFlags = 0;
99
100 setStyle(getStyle() | WS_CLIPCHILDREN);
101
102 updateFrameText(MDI_NOFRAMEREPAINT, getParent()->getWindowNameA());
103
104 AppendMenuA( hWindowMenu, MF_SEPARATOR, 0, NULL );
105
106 setClientRect(frameWnd->getClientRectPtr());
107
108 dprintf(("MDIClient created - hwnd = %04x, idFirst = %u\n", getWindowHandle(), idFirstChild ));
109
110 retvalue = 0;
111 goto END;
112
113 case WM_DESTROY:
114 if( maximizedChild ) restoreFrameMenu(getParent());
115
116 if((nItems = GetMenuItemCount(hWindowMenu)) > 0)
117 {
118 idFirstChild = nItems - 1;
119 nActiveChildren++; /* to delete a separator */
120 while( nActiveChildren-- )
121 DeleteMenu(hWindowMenu,MF_BYPOSITION,idFirstChild--);
122 }
123 retvalue = 0;
124 goto END;
125
126 case WM_MDIACTIVATE:
127 if( activeChild && activeChild->getWindowHandle() != (HWND)wParam )
128 {
129 mdichild = (Win32MDIChildWindow *)GetWindowFromHandle((HWND)wParam);
130 if(mdichild) {
131 mdichild->SetWindowPos(0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE);
132 }
133 }
134 retvalue = 0;
135 goto END;
136
137 case WM_MDICASCADE:
138 retvalue = cascade(wParam);
139 goto END;
140
141 case WM_MDICREATE:
142 if (lParam) {
143 retvalue = Win32MDIChildWindow::createChild( this, (MDICREATESTRUCTA*)lParam );
144 }
145 else retvalue = 0;
146 goto END;
147
148 case WM_MDIDESTROY:
149 mdichild = (Win32MDIChildWindow *)GetWindowFromHandle((HWND)wParam);
150 if(mdichild) {
151 retvalue = destroyChild(mdichild, TRUE );
152 }
153 goto END;
154
155 case WM_MDIGETACTIVE:
156 dprintf(("WM_MDIGETACTIVE: %x %x", this, (activeChild) ? activeChild->getWindowHandle() : 0));
157 if (lParam)
158 *(BOOL *)lParam = (maximizedChild != 0);
159
160 retvalue = (activeChild) ? activeChild->getWindowHandle() : 0;
161 goto END;
162
163 case WM_MDIICONARRANGE:
164 mdiFlags |= MDIF_NEEDUPDATE;
165 ArrangeIconicWindows(Win32Hwnd);
166 sbRecalc = SB_BOTH+1;
167 SendMessageA(WM_MDICALCCHILDSCROLL,0,0L);
168 retvalue = 0;
169 goto END;
170
171 case WM_MDIMAXIMIZE:
172 ::ShowWindow( (HWND)wParam, SW_MAXIMIZE );
173 retvalue = 0;
174 goto END;
175
176 case WM_MDINEXT: /* lParam != 0 means previous window */
177 mdichild = (Win32MDIChildWindow *)GetWindowFromHandle((HWND)wParam);
178 if(mdichild) {
179 switchActiveChild(mdichild, (lParam)? FALSE : TRUE );
180 }
181 break;
182
183 case WM_MDIRESTORE:
184 ::SendMessageA( (HWND)wParam, WM_SYSCOMMAND, SC_RESTORE, 0);
185 retvalue = 0;
186 goto END;
187 case WM_MDISETMENU:
188 retvalue = setMDIMenu((HMENU)wParam, (HMENU)lParam );
189 goto END;
190
191 case WM_MDIREFRESHMENU:
192 retvalue = refreshMDIMenu((HMENU)wParam, (HMENU)lParam );
193 goto END;
194
195 case WM_MDITILE:
196 mdiFlags |= MDIF_NEEDUPDATE;
197 ShowScrollBar(Win32Hwnd,SB_BOTH,FALSE);
198 tile(wParam);
199 mdiFlags &= ~MDIF_NEEDUPDATE;
200 retvalue = 0;
201 goto END;
202
203 case WM_VSCROLL:
204 case WM_HSCROLL:
205 mdiFlags |= MDIF_NEEDUPDATE;
206 ScrollChildren(Win32Hwnd, message, wParam, lParam);
207 mdiFlags &= ~MDIF_NEEDUPDATE;
208 retvalue = 0;
209 goto END;
210
211 case WM_SETFOCUS:
212 if( activeChild )
213 {
214 if( !(activeChild->getStyle() & WS_MINIMIZE) )
215 ::SetFocus(activeChild->getWindowHandle());
216 }
217 retvalue = 0;
218 goto END;
219
220 case WM_NCACTIVATE:
221 if( activeChild )
222 activeChild->SendInternalMessageA(message, wParam, lParam);
223 break;
224
225 case WM_PARENTNOTIFY:
226 if (LOWORD(wParam) == WM_LBUTTONDOWN)
227 {
228 POINTS pt = MAKEPOINTS(lParam);
229 POINT point;
230
231 point.x = pt.x;
232 point.y = pt.y;
233
234 HWND child = ChildWindowFromPoint(getWindowHandle(), point);
235
236 if( child && child != getWindowHandle() && (!activeChild || activeChild->getWindowHandle() != child) )
237 ::SetWindowPos(child, 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE );
238 }
239 retvalue = 0;
240 goto END;
241
242 case WM_SIZE:
243 if( maximizedChild && maximizedChild->IsWindow() )
244 {
245 RECT rect;
246
247 rect.left = 0;
248 rect.top = 0;
249 rect.right = LOWORD(lParam);
250 rect.bottom = HIWORD(lParam);
251
252 AdjustWindowRectEx(&rect, maximizedChild->getStyle(), 0, maximizedChild->getExStyle());
253 ::MoveWindow(maximizedChild->getWindowHandle(), rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, 1);
254 }
255 else postUpdate(SB_BOTH+1);
256 break;
257
258 case WM_MDICALCCHILDSCROLL:
259 if( (mdiFlags & MDIF_NEEDUPDATE) && sbRecalc )
260 {
261 CalcChildScroll(Win32Hwnd, sbRecalc-1);
262 sbRecalc = 0;
263 mdiFlags &= ~MDIF_NEEDUPDATE;
264 }
265 retvalue = 0;
266 goto END;
267 }
268 retvalue = DefWindowProcA(message, wParam, lParam );
269END:
270 return retvalue;
271}
272/**********************************************************************
273 * MDIClientWndProc
274 *
275 * This function handles all MDI requests.
276 */
277LRESULT WINAPI MDIClientWndProc( HWND hwnd, UINT message, WPARAM wParam,
278 LPARAM lParam )
279{
280 Win32MDIClientWindow *window;
281
282 window = (Win32MDIClientWindow *)Win32BaseWindow::GetWindowFromHandle(hwnd);
283 if(!window) {
284 dprintf(("MDIClientWndProc, window %x not found", hwnd));
285 return 0;
286 }
287 return window->MDIClientWndProc(message, wParam, lParam);
288}
289/**********************************************************************
290 * MDI_GetWindow
291 *
292 * returns "activateable" child different from the current or zero
293 */
294Win32MDIChildWindow *Win32MDIClientWindow::getWindow(Win32MDIChildWindow *actchild, BOOL bNext,
295 DWORD dwStyleMask)
296{
297 Win32MDIChildWindow *lastchild = 0, *curchild;
298
299 dwStyleMask |= WS_DISABLED | WS_VISIBLE;
300
301 if( !actchild ) actchild = getActiveChild();
302 if( !actchild) return 0;
303
304 for ( curchild = (Win32MDIChildWindow *)actchild->getNextChild(); ; curchild = (Win32MDIChildWindow *)curchild->getNextChild())
305 {
306 if (!curchild ) curchild = (Win32MDIChildWindow *)getFirstChild();
307
308 if ( curchild == actchild ) break; /* went full circle */
309
310 if (!curchild->getOwner() && (curchild->getStyle() & dwStyleMask) == WS_VISIBLE )
311 {
312 lastchild = curchild;
313 if ( bNext ) break;
314 }
315 }
316 return lastchild;
317}
318/**********************************************************************
319 * MDI_ChildActivate
320 *
321 * Note: hWndChild is NULL when last child is being destroyed
322 */
323LONG Win32MDIClientWindow::childActivate(Win32MDIChildWindow *child)
324{
325 BOOL isActiveFrameWnd = 0;
326 LONG retvalue;
327 Win32MDIChildWindow *prevActive = activeChild;
328
329 if( child && child->getStyle() & WS_DISABLED )
330 {
331 return 0;
332 }
333
334 /* Don't activate if it is already active. Might happen
335 since ShowWindow DOES activate MDI children */
336 if(activeChild == child)
337 {
338 return 0;
339 }
340
341 if( GetActiveWindow() == getParent()->getWindowHandle())
342 isActiveFrameWnd = TRUE;
343
344 /* deactivate prev. active child */
345 if( prevActive )
346 {
347 prevActive->setStyle(prevActive->getStyle() | WS_SYSMENU);
348 prevActive->SendInternalMessageA( WM_NCACTIVATE, FALSE, 0L );
349 prevActive->SendInternalMessageA( WM_MDIACTIVATE, (WPARAM)prevActive->getWindowHandle(), (LPARAM)(child) ? child->getWindowHandle() : 0);
350
351 /* uncheck menu item */
352 if( getMDIMenu() )
353 CheckMenuItem(getMDIMenu(), prevActive->getWindowId(), 0);
354 }
355
356 /* set appearance */
357 if( maximizedChild)
358 {
359 if( maximizedChild != child) {
360 if( child ) {
361 activeChild = child;
362 child->ShowWindow(SW_SHOWMAXIMIZED);
363 }
364 else
365 if(activeChild) activeChild->ShowWindow( SW_SHOWNORMAL );
366 }
367 }
368
369 dprintf(("childActivate: %x %x", this, (child) ? child->getWindowHandle() : 0));
370 activeChild = child;
371
372 /* check if we have any children left */
373 if( !activeChild )
374 {
375 if( isActiveFrameWnd )
376 SetFocus(getWindowHandle());
377
378 return 0;
379 }
380
381 /* check menu item */
382 if( getMDIMenu() )
383 CheckMenuItem(getMDIMenu(), child->getWindowId(), MF_CHECKED);
384
385 /* bring active child to the top */
386 child->SetWindowPos( 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
387
388 if( isActiveFrameWnd )
389 {
390 child->SendInternalMessageA( WM_NCACTIVATE, TRUE, 0L);
391 if( GetFocus() == getWindowHandle())
392 SendInternalMessageA( WM_SETFOCUS, (WPARAM)getWindowHandle(), 0L );
393 else
394 SetFocus( getWindowHandle() );
395 }
396
397 /* @@@PH prevActive may be NULL actually ?! */
398 child->SendInternalMessageA( WM_MDIACTIVATE,
399 prevActive ? (WPARAM)prevActive->getWindowHandle() : 0,
400 child->getWindowHandle());
401 return TRUE;
402}
403/**********************************************************************
404 * MDI_SwitchActiveChild
405 *
406 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
407 * being activated
408 */
409void Win32MDIClientWindow::switchActiveChild(Win32MDIChildWindow *nextActiveChild, BOOL bNextWindow )
410{
411 Win32MDIChildWindow *prevActiveChild = 0;
412
413 if ( !nextActiveChild) return; /* no window to switch to */
414
415 prevActiveChild = getActiveChild();
416
417 if ( prevActiveChild != nextActiveChild)
418 {
419 BOOL bOptimize = 0;
420
421 if( getMaximizedChild() )
422 {
423 bOptimize = 1;
424 nextActiveChild->setStyle(nextActiveChild->getStyle()& ~WS_VISIBLE);
425 }
426
427 nextActiveChild->SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
428
429 if( bNextWindow && prevActiveChild )
430 prevActiveChild->SetWindowPos(HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
431
432 if( bOptimize )
433 ShowWindow(SW_SHOW );
434 }
435}
436
437
438/**********************************************************************
439 * MDIDestroyChild
440 */
441LRESULT Win32MDIClientWindow::destroyChild(Win32MDIChildWindow *child, BOOL flagDestroy )
442{
443 if( child == getActiveChild())
444 {
445 switchActiveChild(child, TRUE);
446
447 if( child == getActiveChild() )
448 {
449 ::ShowWindow(child->getWindowHandle(),SW_HIDE);
450 if( child == getMaximizedChild() )
451 {
452 restoreFrameMenu(child);
453 setMaximizedChild(NULL);
454 updateFrameText(TRUE,NULL);
455 }
456 childActivate(0);
457 }
458 }
459 child->menuDeleteItem();
460
461 decNrActiveChildren();
462
463 dprintf(("child destroyed - %04x\n", child->getWindowHandle()));
464
465 if (flagDestroy)
466 {
467 postUpdate(SB_BOTH+1);
468 ::DestroyWindow(child->getWindowHandle());
469 }
470
471 return 0;
472}
473/**********************************************************************
474 * MDI_UpdateFrameText
475 *
476 * used when child window is maximized/restored
477 *
478 * Note: lpTitle can be NULL
479 */
480void Win32MDIClientWindow::updateFrameText(BOOL repaint, LPCSTR lpTitle )
481{
482 char lpBuffer[MDI_MAXTITLELENGTH+1];
483
484 /* store new "default" title if lpTitle is not NULL */
485 if (lpTitle)
486 {
487 if (frameTitle) HeapFree( GetProcessHeap(), 0, frameTitle );
488 frameTitle = HEAP_strdupA( GetProcessHeap(), 0, lpTitle );
489 }
490
491 if (frameTitle)
492 {
493 Win32MDIChildWindow *childWnd = getMaximizedChild();
494
495 if( childWnd && childWnd->getWindowNameA() )
496 {
497 /* combine frame title and child title if possible */
498
499 LPCSTR lpBracket = " - [";
500 int i_frame_text_length = strlen(frameTitle);
501 int i_child_text_length = strlen(childWnd->getWindowNameA());
502
503 lstrcpynA( lpBuffer, frameTitle, MDI_MAXTITLELENGTH);
504
505 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
506 {
507 strcat( lpBuffer, lpBracket );
508
509 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
510 {
511 strcat( lpBuffer, childWnd->getWindowNameA());
512 strcat( lpBuffer, "]" );
513 }
514 else
515 {
516 lstrcpynA(lpBuffer + i_frame_text_length + 4,
517 childWnd->getWindowNameA(), MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
518 strcat( lpBuffer, "]" );
519 }
520 }
521 }
522 else
523 {
524 lstrcpynA(lpBuffer, frameTitle, MDI_MAXTITLELENGTH );
525 lpBuffer[MDI_MAXTITLELENGTH]='\0';
526 }
527 }
528 else
529 lpBuffer[0] = '\0';
530
531 getParent()->SetWindowTextA(lpBuffer);
532 if( repaint == MDI_REPAINTFRAME)
533 getParent()->SetWindowPos(0,0,0,0,0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
534}
535/**********************************************************************
536 * MDISetMenu
537 */
538LRESULT Win32MDIClientWindow::setMDIMenu(HMENU hmenuFrame, HMENU hmenuWindow)
539{
540 HWND hwndFrame = ::GetParent(getWindowHandle());
541 HMENU oldFrameMenu = ::GetMenu(hwndFrame);
542
543 if( maximizedChild && hmenuFrame && hmenuFrame!=oldFrameMenu )
544 restoreFrameMenu(maximizedChild);
545
546 if( hmenuWindow && hmenuWindow != hWindowMenu )
547 {
548 /* delete menu items from ci->hWindowMenu
549 * and add them to hmenuWindow */
550
551 INT i = GetMenuItemCount(hWindowMenu) - 1;
552 INT pos = GetMenuItemCount(hmenuWindow) + 1;
553
554 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
555
556 if( nActiveChildren )
557 {
558 INT j = i - nActiveChildren + 1;
559 char buffer[100];
560 UINT id,state;
561
562 for( ; i >= j ; i-- )
563 {
564 id = GetMenuItemID(hWindowMenu,i );
565 state = GetMenuState(hWindowMenu,i,MF_BYPOSITION);
566
567 GetMenuStringA(hWindowMenu, i, buffer, 100, MF_BYPOSITION);
568
569 DeleteMenu(hWindowMenu, i , MF_BYPOSITION);
570 InsertMenuA(hmenuWindow, pos, MF_BYPOSITION | MF_STRING,
571 id, buffer);
572 CheckMenuItem(hmenuWindow ,pos , MF_BYPOSITION | (state & MF_CHECKED));
573 }
574 }
575
576 /* remove separator */
577 DeleteMenu(hWindowMenu, i, MF_BYPOSITION);
578
579 hWindowMenu = hmenuWindow;
580 }
581
582 if( hmenuFrame && hmenuFrame!=oldFrameMenu)
583 {
584 ::SetMenu(hwndFrame, hmenuFrame);
585
586 if (maximizedChild)
587 augmentFrameMenu(maximizedChild);
588
589 return oldFrameMenu;
590 }
591 return 0;
592}
593
594/**********************************************************************
595 * MDIRefreshMenu
596 */
597LRESULT Win32MDIClientWindow::refreshMDIMenu(HMENU hmenuFrame, HMENU hmenuWindow)
598{
599 HMENU oldFrameMenu = getParent()->GetMenu();
600
601// FIXME("partially function stub\n");
602
603 return oldFrameMenu;
604}
605/**********************************************************************
606 * MDI_RestoreFrameMenu
607 */
608BOOL Win32MDIClientWindow::restoreFrameMenu(Win32BaseWindow *child)
609{
610 MENUITEMINFOA menuInfo;
611 INT nItems = GetMenuItemCount(getParent()->GetMenu()) - 1;
612 UINT iId = GetMenuItemID(getParent()->GetMenu(),nItems) ;
613
614 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
615 return 0;
616
617 /*
618 * Remove the system menu, If that menu is the icon of the window
619 * as it is in win95, we have to delete the bitmap.
620 */
621 menuInfo.cbSize = sizeof(MENUITEMINFOA);
622 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
623
624 GetMenuItemInfoA(getParent()->GetMenu(),
625 0,
626 TRUE,
627 &menuInfo);
628
629 RemoveMenu(getParent()->GetMenu(),0,MF_BYPOSITION);
630
631//TODO: See augmentframemenu
632#if 0
633 if ((menuInfo.fType & MFT_BITMAP) &&
634 (LOWORD(menuInfo.dwTypeData)!=0) &&
635 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
636 {
637 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
638 }
639#endif
640
641 /* close */
642 DeleteMenu(getParent()->GetMenu(),GetMenuItemCount(getParent()->GetMenu()) - 1,MF_BYPOSITION);
643
644 /* restore */
645 DeleteMenu(getParent()->GetMenu(),GetMenuItemCount(getParent()->GetMenu()) - 1,MF_BYPOSITION);
646 /* minimize */
647 DeleteMenu(getParent()->GetMenu(),GetMenuItemCount(getParent()->GetMenu()) - 1,MF_BYPOSITION);
648
649 DrawMenuBar(getParent()->getWindowHandle());
650
651 return 1;
652}
653
654Win32BaseWindow** Win32MDIClientWindow::buildWindowArray(UINT bwaFlags,PUINT total)
655{
656 Win32BaseWindow **list = NULL,*win32wnd,**pos;
657 UINT skipHidden;
658 DWORD skipFlags;
659
660 skipHidden = bwaFlags & BWA_SKIPHIDDEN;
661 skipFlags = (bwaFlags & BWA_SKIPDISABLED) ? WS_DISABLED : 0;
662 if (bwaFlags & BWA_SKIPICONIC) skipFlags |= WS_MINIMIZE;
663
664 /* First count the windows */
665 *total = 0;
666 win32wnd = (Win32BaseWindow*)this->getFirstChild();
667 while (win32wnd)
668 {
669 if (!(win32wnd->getStyle() & skipFlags) && (!skipHidden || (win32wnd->getStyle() & WS_VISIBLE)))
670 (*total)++;
671 win32wnd = (Win32BaseWindow*)win32wnd->getNextChild();
672 }
673
674 if (*total)
675 {
676 /* Now build the list of all windows */
677 list = (Win32BaseWindow**)HeapAlloc(GetProcessHeap(),0,sizeof(Win32BaseWindow*)*(*total+1));
678 if (list)
679 {
680 for (win32wnd = (Win32BaseWindow*)this->getFirstChild(),pos = list;win32wnd;win32wnd = (Win32BaseWindow*)win32wnd->getNextChild())
681 {
682 if ((win32wnd->getStyle() & skipFlags));
683 else if(!skipHidden || win32wnd->getStyle() & WS_VISIBLE)
684 *pos++ = win32wnd;
685 }
686 *pos = NULL;
687 }
688 }
689
690 return list;
691}
692
693void Win32MDIClientWindow::releaseWindowArray(Win32BaseWindow **wndArray)
694{
695 HeapFree(GetProcessHeap(),0,wndArray);
696}
697
698/**********************************************************************
699 * MDI_CalcDefaultChildPos
700 *
701 * It seems that the default height is about 2/3 of the client rect
702 */
703void Win32MDIClientWindow::calcDefaultChildPos(WORD n,LPPOINT lpPos,INT delta)
704{
705 INT nstagger;
706 RECT rect;
707 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
708 GetSystemMetrics(SM_CYFRAME) - 1;
709
710 getClientRect(&rect);
711 if( rect.bottom - rect.top - delta >= spacing )
712 rect.bottom -= delta;
713
714 nstagger = (rect.bottom - rect.top)/(3 * spacing);
715 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
716 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
717 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
718}
719
720/**********************************************************************
721 * MDICascade
722 */
723BOOL Win32MDIClientWindow::cascade(UINT fuCascade)
724{
725 Win32BaseWindow **list;
726 UINT total = 0;
727
728 if (getMaximizedChild())
729 SendInternalMessageA(WM_MDIRESTORE, (WPARAM)getMaximizedChild()->getWindowHandle(), 0);
730
731 if (nActiveChildren == 0) return 0;
732
733 list = buildWindowArray(BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC,&total);
734 if (list)
735 {
736 Win32BaseWindow** heapPtr = list;
737 if (total)
738 {
739 INT delta = 0,n = 0;
740 POINT pos[2];
741
742
743 if (total < nActiveChildren)
744 delta = GetSystemMetrics(SM_CYICONSPACING)+GetSystemMetrics(SM_CYICON);
745
746 // walk the list (backwards) and move windows
747 while (*list) list++;
748 while (list != heapPtr)
749 {
750 list--;
751
752 calcDefaultChildPos(n++,pos,delta);
753 ::SetWindowPos((*list)->getWindowHandle(),0,pos[0].x,pos[0].y,pos[1].x,pos[1].y,SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
754 }
755 }
756 releaseWindowArray(heapPtr);
757 }
758
759 if (total < nActiveChildren)
760 ArrangeIconicWindows(Win32Hwnd);
761
762 return TRUE;
763}
764
765/**********************************************************************
766 * MDITile
767 */
768BOOL Win32MDIClientWindow::tile(UINT fuTile)
769{
770 Win32BaseWindow** list;
771 UINT total = 0;
772
773 if (getMaximizedChild())
774 SendInternalMessageA(WM_MDIRESTORE, (WPARAM)getMaximizedChild()->getWindowHandle(), 0);
775
776 if (nActiveChildren == 0) return TRUE;
777
778 list = buildWindowArray(BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
779 ((fuTile & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
780
781 if (list)
782 {
783 Win32BaseWindow** heapPtr = list;
784
785 if (total)
786 {
787 RECT rect;
788 int x, y, xsize, ysize;
789 int rows, columns, r, c, i;
790
791 GetClientRect(Win32Hwnd,&rect);
792 rows = (int) sqrt((double)total);
793 columns = total / rows;
794
795 if( fuTile & MDITILE_HORIZONTAL ) // version >= 3.1
796 {
797 i = rows;
798 rows = columns; // exchange r and c
799 columns = i;
800 }
801
802 if( total != nActiveChildren)
803 {
804 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
805 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
806 }
807
808 ysize = rect.bottom / rows;
809 xsize = rect.right / columns;
810
811 for (x = i = 0, c = 1; c <= columns && *list; c++)
812 {
813 if (c == columns)
814 {
815 rows = total - i;
816 ysize = rect.bottom / rows;
817 }
818
819 y = 0;
820 for (r = 1; r <= rows && *list; r++, i++)
821 {
822 ::SetWindowPos((*list)->getWindowHandle(), 0, x, y, xsize, ysize,
823 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
824 y += ysize;
825 list++;
826 }
827 x += xsize;
828 }
829 }
830 releaseWindowArray(heapPtr);
831 }
832
833 if( total < nActiveChildren ) ArrangeIconicWindows(Win32Hwnd);
834
835 return TRUE;
836}
837
838/* ----------------------- Frame window ---------------------------- */
839
840/**********************************************************************
841 * MDI_AugmentFrameMenu
842 */
843BOOL Win32MDIClientWindow::augmentFrameMenu(Win32MDIChildWindow *child)
844{
845 HMENU hSysPopup = 0,hFrameMenu = ::GetMenu(getParent()->getWindowHandle()),hSysMenu = ::GetSystemMenu(child->getWindowHandle(),FALSE);
846 HBITMAP hSysMenuBitmap = 0;
847
848 if (!hFrameMenu || !hSysMenu)
849 return 0;
850
851 // create a copy of sysmenu popup and insert it into frame menu bar
852
853 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
854 return 0;
855
856 //TRACE("\tgot popup %04x in sysmenu %04x\n",
857 // hSysPopup, child->hSysMenu);
858
859 AppendMenuA(hFrameMenu,MF_HELP | MF_BITMAP,
860 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
861 AppendMenuA(hFrameMenu,MF_HELP | MF_BITMAP,
862 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
863
864 // In Win 95 look, the system menu is replaced by the child icon
865
866 /* Find icon */
867 HICON hIcon = child->IconForWindow(ICON_SMALL);
868
869 if (hIcon)
870 {
871 HDC hMemDC;
872 HBITMAP hBitmap, hOldBitmap;
873 HBRUSH hBrush;
874 HDC hdc = GetDC(child->getWindowHandle());
875
876 if (hdc)
877 {
878 int cx, cy;
879
880 cx = GetSystemMetrics(SM_CXSMICON);
881 cy = GetSystemMetrics(SM_CYSMICON);
882 hMemDC = CreateCompatibleDC(hdc);
883 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
884 hOldBitmap = SelectObject(hMemDC, hBitmap);
885 SetMapMode(hMemDC, MM_TEXT);
886 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
887 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
888 SelectObject (hMemDC, hOldBitmap);
889 DeleteObject(hBrush);
890 DeleteDC(hMemDC);
891 ReleaseDC(child->getWindowHandle(), hdc);
892 hSysMenuBitmap = hBitmap;
893 }
894 }
895
896 if( !InsertMenuA(hFrameMenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
897 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
898 {
899 //TRACE("not inserted\n");
900 DestroyMenu(hSysPopup);
901 return 0;
902 }
903
904 // The close button is only present in Win 95 look
905
906 AppendMenuA(hFrameMenu,MF_HELP | MF_BITMAP,
907 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
908
909 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
910 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
911 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
912 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
913
914 // redraw menu
915 DrawMenuBar(getParent()->getWindowHandle());
916
917 return 1;
918}
919
920/**********************************************************************
921 * MDI_RestoreFrameMenu
922 */
923BOOL Win32MDIClientWindow::restoreFrameMenu(Win32MDIChildWindow *child)
924{
925 MENUITEMINFOA menuInfo;
926 HMENU hFrameMenu = ::GetMenu(getParent()->getWindowHandle());
927 INT nItems = GetMenuItemCount(hFrameMenu) - 1;
928 UINT iId = GetMenuItemID(hFrameMenu,nItems) ;
929
930 //TRACE("frameWnd %p,child %04x\n",frameWnd,hChild);
931
932 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
933 return 0;
934
935 /*
936 * Remove the system menu, If that menu is the icon of the window
937 * as it is in win95, we have to delete the bitmap.
938 */
939
940 menuInfo.cbSize = sizeof(MENUITEMINFOA);
941 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
942
943 GetMenuItemInfoA(hFrameMenu,
944 0,
945 TRUE,
946 &menuInfo);
947
948 RemoveMenu(hFrameMenu,0,MF_BYPOSITION);
949
950#if 0 //CB: hBmpClose not (yet) defined
951 if ( (menuInfo.fType & MFT_BITMAP) &&
952 (LOWORD(menuInfo.dwTypeData)!=0) &&
953 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
954 {
955 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
956 }
957#endif
958
959 // close
960 DeleteMenu(hFrameMenu,GetMenuItemCount(hFrameMenu) - 1,MF_BYPOSITION);
961
962 // restore
963 DeleteMenu(hFrameMenu,GetMenuItemCount(hFrameMenu) - 1,MF_BYPOSITION);
964 // minimize
965 DeleteMenu(hFrameMenu,GetMenuItemCount(hFrameMenu) - 1,MF_BYPOSITION);
966
967 DrawMenuBar(getParent()->getWindowHandle());
968
969 return 1;
970}
971
972/***********************************************************************
973 * CalcChildScroll (USER.462)
974 */
975void WINAPI CalcChildScroll(HWND hwnd,WORD scroll)
976{
977 Win32BaseWindow *win32wnd = Win32BaseWindow::GetWindowFromHandle(hwnd);
978 SCROLLINFO info;
979 RECT childRect, clientRect;
980 INT vmin, vmax, hmin, hmax, vpos, hpos;
981
982 if (!win32wnd) return;
983
984 GetClientRect( hwnd, &clientRect );
985 SetRectEmpty( &childRect );
986
987 //TODO: Check if this goes correctly
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)GetStockObject(GRAY_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.