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

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

new mapping functions, fixed 1 pixel and window handle bugs

File size: 37.7 KB
Line 
1/* $Id: win32wmdiclient.cpp,v 1.20 1999-12-29 22:54:03 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->getClientRect());
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 = *this->getClientRect();
697 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
698 GetSystemMetrics(SM_CYFRAME) - 1;
699
700 if( rect.bottom - rect.top - delta >= spacing )
701 rect.bottom -= delta;
702
703 nstagger = (rect.bottom - rect.top)/(3 * spacing);
704 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
705 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
706 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
707}
708
709/**********************************************************************
710 * MDICascade
711 */
712BOOL Win32MDIClientWindow::cascade(UINT fuCascade)
713{
714 Win32BaseWindow **list;
715 UINT total = 0;
716
717 if (getMaximizedChild())
718 SendInternalMessageA(WM_MDIRESTORE, (WPARAM)getMaximizedChild()->getWindowHandle(), 0);
719
720 if (nActiveChildren == 0) return 0;
721
722 list = buildWindowArray(BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC,&total);
723 if (list)
724 {
725 Win32BaseWindow** heapPtr = list;
726 if (total)
727 {
728 INT delta = 0,n = 0;
729 POINT pos[2];
730
731
732 if (total < nActiveChildren)
733 delta = GetSystemMetrics(SM_CYICONSPACING)+GetSystemMetrics(SM_CYICON);
734
735 // walk the list (backwards) and move windows
736 while (*list) list++;
737 while (list != heapPtr)
738 {
739 list--;
740
741 calcDefaultChildPos(n++,pos,delta);
742 ::SetWindowPos((*list)->getWindowHandle(),0,pos[0].x,pos[0].y,pos[1].x,pos[1].y,SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
743 }
744 }
745 releaseWindowArray(heapPtr);
746 }
747
748 if (total < nActiveChildren)
749 ArrangeIconicWindows(Win32Hwnd);
750
751 return TRUE;
752}
753
754/**********************************************************************
755 * MDITile
756 */
757BOOL Win32MDIClientWindow::tile(UINT fuTile)
758{
759 Win32BaseWindow** list;
760 UINT total = 0;
761
762 if (getMaximizedChild())
763 SendInternalMessageA(WM_MDIRESTORE, (WPARAM)getMaximizedChild()->getWindowHandle(), 0);
764
765 if (nActiveChildren == 0) return TRUE;
766
767 list = buildWindowArray(BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
768 ((fuTile & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
769
770 if (list)
771 {
772 Win32BaseWindow** heapPtr = list;
773
774 if (total)
775 {
776 RECT rect;
777 int x, y, xsize, ysize;
778 int rows, columns, r, c, i;
779
780 GetClientRect(Win32Hwnd,&rect);
781 rows = (int) sqrt((double)total);
782 columns = total / rows;
783
784 if( fuTile & MDITILE_HORIZONTAL ) // version >= 3.1
785 {
786 i = rows;
787 rows = columns; // exchange r and c
788 columns = i;
789 }
790
791 if( total != nActiveChildren)
792 {
793 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
794 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
795 }
796
797 ysize = rect.bottom / rows;
798 xsize = rect.right / columns;
799
800 for (x = i = 0, c = 1; c <= columns && *list; c++)
801 {
802 if (c == columns)
803 {
804 rows = total - i;
805 ysize = rect.bottom / rows;
806 }
807
808 y = 0;
809 for (r = 1; r <= rows && *list; r++, i++)
810 {
811 ::SetWindowPos((*list)->getWindowHandle(), 0, x, y, xsize, ysize,
812 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
813 y += ysize;
814 list++;
815 }
816 x += xsize;
817 }
818 }
819 releaseWindowArray(heapPtr);
820 }
821
822 if( total < nActiveChildren ) ArrangeIconicWindows(Win32Hwnd);
823
824 return TRUE;
825}
826
827/* ----------------------- Frame window ---------------------------- */
828
829/**********************************************************************
830 * MDI_AugmentFrameMenu
831 */
832BOOL Win32MDIClientWindow::augmentFrameMenu(Win32MDIChildWindow *child)
833{
834 HMENU hSysPopup = 0,hFrameMenu = ::GetMenu(getParent()->getWindowHandle()),hSysMenu = GetSystemMenu(child->getWindowHandle(),FALSE);
835 HBITMAP hSysMenuBitmap = 0;
836
837 if (!hFrameMenu || !hSysMenu)
838 return 0;
839
840 // create a copy of sysmenu popup and insert it into frame menu bar
841
842 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
843 return 0;
844
845 //TRACE("\tgot popup %04x in sysmenu %04x\n",
846 // hSysPopup, child->hSysMenu);
847
848 AppendMenuA(hFrameMenu,MF_HELP | MF_BITMAP,
849 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
850 AppendMenuA(hFrameMenu,MF_HELP | MF_BITMAP,
851 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
852
853 // In Win 95 look, the system menu is replaced by the child icon
854
855 HICON hIcon = GetClassLongA(child->getWindowHandle(), GCL_HICONSM);
856 if (!hIcon)
857 hIcon = GetClassLongA(child->getWindowHandle(), GCL_HICON);
858 if (hIcon)
859 {
860 HDC hMemDC;
861 HBITMAP hBitmap, hOldBitmap;
862 HBRUSH hBrush;
863 HDC hdc = GetDC(child->getWindowHandle());
864
865 if (hdc)
866 {
867 int cx, cy;
868
869 cx = GetSystemMetrics(SM_CXSMICON);
870 cy = GetSystemMetrics(SM_CYSMICON);
871 hMemDC = CreateCompatibleDC(hdc);
872 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
873 hOldBitmap = SelectObject(hMemDC, hBitmap);
874 SetMapMode(hMemDC, MM_TEXT);
875 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
876 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
877 SelectObject (hMemDC, hOldBitmap);
878 DeleteObject(hBrush);
879 DeleteDC(hMemDC);
880 ReleaseDC(child->getWindowHandle(), hdc);
881 hSysMenuBitmap = hBitmap;
882 }
883 }
884
885 if( !InsertMenuA(hFrameMenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
886 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
887 {
888 //TRACE("not inserted\n");
889 DestroyMenu(hSysPopup);
890 return 0;
891 }
892
893 // The close button is only present in Win 95 look
894
895 AppendMenuA(hFrameMenu,MF_HELP | MF_BITMAP,
896 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
897
898 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
899 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
900 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
901 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
902
903 // redraw menu
904 DrawMenuBar(getParent()->getWindowHandle());
905
906 return 1;
907}
908
909/**********************************************************************
910 * MDI_RestoreFrameMenu
911 */
912BOOL Win32MDIClientWindow::restoreFrameMenu(Win32MDIChildWindow *child)
913{
914 MENUITEMINFOA menuInfo;
915 HMENU hFrameMenu = ::GetMenu(getParent()->getWindowHandle());
916 INT nItems = GetMenuItemCount(hFrameMenu) - 1;
917 UINT iId = GetMenuItemID(hFrameMenu,nItems) ;
918
919 //TRACE("frameWnd %p,child %04x\n",frameWnd,hChild);
920
921 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
922 return 0;
923
924 /*
925 * Remove the system menu, If that menu is the icon of the window
926 * as it is in win95, we have to delete the bitmap.
927 */
928
929 menuInfo.cbSize = sizeof(MENUITEMINFOA);
930 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
931
932 GetMenuItemInfoA(hFrameMenu,
933 0,
934 TRUE,
935 &menuInfo);
936
937 RemoveMenu(hFrameMenu,0,MF_BYPOSITION);
938
939#if 0 //CB: hBmpClose not (yet) defined
940 if ( (menuInfo.fType & MFT_BITMAP) &&
941 (LOWORD(menuInfo.dwTypeData)!=0) &&
942 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
943 {
944 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
945 }
946#endif
947
948 // close
949 DeleteMenu(hFrameMenu,GetMenuItemCount(hFrameMenu) - 1,MF_BYPOSITION);
950
951 // restore
952 DeleteMenu(hFrameMenu,GetMenuItemCount(hFrameMenu) - 1,MF_BYPOSITION);
953 // minimize
954 DeleteMenu(hFrameMenu,GetMenuItemCount(hFrameMenu) - 1,MF_BYPOSITION);
955
956 DrawMenuBar(getParent()->getWindowHandle());
957
958 return 1;
959}
960
961/***********************************************************************
962 * CalcChildScroll (USER.462)
963 */
964void WINAPI CalcChildScroll(HWND hwnd,WORD scroll)
965{
966 Win32BaseWindow *win32wnd = Win32BaseWindow::GetWindowFromHandle(hwnd);
967 SCROLLINFO info;
968 RECT childRect, clientRect;
969 INT vmin, vmax, hmin, hmax, vpos, hpos;
970
971 if (!win32wnd) return;
972
973 GetClientRect( hwnd, &clientRect );
974 SetRectEmpty( &childRect );
975
976 for (win32wnd = (Win32BaseWindow*)win32wnd->getFirstChild();win32wnd;win32wnd = (Win32BaseWindow*)win32wnd->getNextChild())
977 {
978 if( win32wnd->getStyle() & WS_MAXIMIZE )
979 {
980 ShowScrollBar(hwnd, SB_BOTH, FALSE);
981 return;
982 }
983 UnionRect(&childRect,win32wnd->getWindowRect(),&childRect);
984 }
985 UnionRect( &childRect, &clientRect, &childRect );
986
987 hmin = childRect.left; hmax = childRect.right - clientRect.right;
988 hpos = clientRect.left - childRect.left;
989 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
990 vpos = clientRect.top - childRect.top;
991
992 switch( scroll )
993 {
994 case SB_HORZ:
995 vpos = hpos; vmin = hmin; vmax = hmax;
996 case SB_VERT:
997 info.cbSize = sizeof(info);
998 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
999 info.fMask = SIF_POS | SIF_RANGE;
1000 SetScrollInfo(hwnd, scroll, &info, TRUE);
1001 break;
1002 case SB_BOTH:
1003 {
1004 SCROLLINFO vInfo, hInfo;
1005
1006 vInfo.cbSize = hInfo.cbSize = sizeof(SCROLLINFO);
1007 vInfo.nMin = vmin;
1008 hInfo.nMin = hmin;
1009 vInfo.nMax = vmax;
1010 hInfo.nMax = hmax;
1011 vInfo.nPos = vpos;
1012 hInfo.nPos = hpos;
1013 vInfo.fMask = hInfo.fMask = SIF_RANGE | SIF_POS;
1014
1015 SetScrollInfo(hwnd,SB_VERT,&vInfo,TRUE);
1016 SetScrollInfo(hwnd,SB_HORZ,&hInfo,TRUE);
1017 }
1018 }
1019}
1020
1021/***********************************************************************
1022 * ScrollChildren32 (USER32.448)
1023 */
1024void WINAPI ScrollChildren(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
1025{
1026 Win32BaseWindow *win32wnd = Win32BaseWindow::GetWindowFromHandle(hWnd);
1027 INT newPos = -1;
1028 INT curPos, length, minPos, maxPos, shift;
1029
1030 if (!win32wnd) return;
1031
1032 if (uMsg == WM_HSCROLL)
1033 {
1034 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
1035 curPos = GetScrollPos(hWnd,SB_HORZ);
1036 length = win32wnd->getClientWidth()/2;
1037 shift = GetSystemMetrics(SM_CYHSCROLL);
1038 } else if (uMsg == WM_VSCROLL)
1039 {
1040 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
1041 curPos = GetScrollPos(hWnd,SB_VERT);
1042 length = win32wnd->getClientHeight()/2;
1043 shift = GetSystemMetrics(SM_CXVSCROLL);
1044 } else return;
1045
1046 switch( wParam )
1047 {
1048 case SB_LINEUP:
1049 newPos = curPos - shift;
1050 break;
1051
1052 case SB_LINEDOWN:
1053 newPos = curPos + shift;
1054 break;
1055
1056 case SB_PAGEUP:
1057 newPos = curPos - length;
1058 break;
1059
1060 case SB_PAGEDOWN:
1061 newPos = curPos + length;
1062 break;
1063
1064 case SB_THUMBPOSITION:
1065 newPos = LOWORD(lParam);
1066 break;
1067
1068 case SB_THUMBTRACK:
1069 return;
1070
1071 case SB_TOP:
1072 newPos = minPos;
1073 break;
1074
1075 case SB_BOTTOM:
1076 newPos = maxPos;
1077 break;
1078
1079 case SB_ENDSCROLL:
1080 CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
1081 return;
1082 }
1083
1084 if( newPos > maxPos )
1085 newPos = maxPos;
1086 else
1087 if( newPos < minPos )
1088 newPos = minPos;
1089
1090 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
1091
1092 if( uMsg == WM_VSCROLL )
1093 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
1094 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1095 else
1096 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
1097 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1098}
1099
1100/*****************************************************************************
1101 * Name : WORD WIN32API CascadeWindows
1102 * Purpose : The CascadeWindows function cascades the specified windows or
1103 * the child windows of the specified parent window.
1104 * Parameters: HWND hwndParent handle of parent window
1105 * UINT wHow types of windows not to arrange
1106 * CONST RECT * lpRect rectangle to arrange windows in
1107 * UINT cKids number of windows to arrange
1108 * const HWND FAR * lpKids array of window handles
1109 * Variables :
1110 * Result : If the function succeeds, the return value is the number of windows arranged.
1111 * If the function fails, the return value is zero.
1112 * Remark :
1113 * Status : UNTESTED STUB
1114 *
1115 * Author : Patrick Haller [Thu, 1998/02/26 11:55]
1116 *****************************************************************************/
1117WORD WIN32API CascadeWindows(HWND hwndParent,
1118 UINT wHow,
1119 CONST LPRECT lpRect,
1120 UINT cKids,
1121 const HWND *lpKids)
1122{
1123 dprintf(("USER32:CascadeWindows(%08xh,%u,%08xh,%u,%08x) not implemented.\n",
1124 hwndParent,
1125 wHow,
1126 lpRect,
1127 cKids,
1128 lpKids));
1129
1130 return (0);
1131}
1132
1133/*****************************************************************************
1134 * Name : BOOL WIN32API CascadeChildWindows
1135 * Purpose : Unknown
1136 * Parameters: Unknown
1137 * Variables :
1138 * Result :
1139 * Remark :
1140 * Status : UNTESTED UNKNOWN STUB
1141 *
1142 * Author : Patrick Haller [Wed, 1998/06/16 11:55]
1143 *****************************************************************************/
1144BOOL WIN32API CascadeChildWindows(DWORD x1,
1145 DWORD x2)
1146{
1147 dprintf(("USER32: CascadeChildWindows(%08xh,%08xh) not implemented.\n",
1148 x1,
1149 x2));
1150
1151 return (FALSE); /* default */
1152}
1153
1154/*****************************************************************************
1155 * Name : WORD WIN32API TileWindows
1156 * Purpose : The TileWindows function tiles the specified windows, or the child
1157 * windows of the specified parent window.
1158 * Parameters: HWND hwndParent handle of parent window
1159 * WORD wFlags types of windows not to arrange
1160 * LPCRECT lpRect rectangle to arrange windows in
1161 * WORD cChildrenb number of windows to arrange
1162 * const HWND *ahwndChildren array of window handles
1163 * Variables :
1164 * Result : If the function succeeds, the return value is the number of
1165 * windows arranged.
1166 * If the function fails, the return value is zero.
1167 * Remark :
1168 * Status : UNTESTED STUB
1169 *
1170 * Author : Patrick Haller [Thu, 1998/02/26 11:55]
1171 *****************************************************************************/
1172WORD WIN32API TileWindows(HWND hwndParent,
1173 UINT wFlags,
1174 const LPRECT lpRect,
1175 UINT cChildrenb,
1176 const HWND *ahwndChildren)
1177{
1178 dprintf(("USER32:TileWindows (%08xh,%08xh,%08xh,%08xh,%08x) not implemented.\n",
1179 hwndParent,
1180 wFlags,
1181 lpRect,
1182 cChildrenb,
1183 ahwndChildren));
1184
1185 return (0);
1186}
1187
1188/*****************************************************************************
1189 * Name : BOOL WIN32API TileChildWindows
1190 * Purpose : Unknown
1191 * Parameters: Unknown
1192 * Variables :
1193 * Result :
1194 * Remark :
1195 * Status : UNTESTED UNKNOWN STUB
1196 *
1197 * Author : Patrick Haller [Wed, 1998/06/16 11:55]
1198 *****************************************************************************/
1199BOOL WIN32API TileChildWindows(DWORD x1,
1200 DWORD x2)
1201{
1202 dprintf(("USER32: TileChildWindows(%08xh,%08xh) not implemented.\n",
1203 x1,
1204 x2));
1205
1206 return (FALSE); /* default */
1207}
1208
1209/* -------- Miscellaneous service functions ----------
1210 *
1211 * MDI_GetChildByID
1212 */
1213Win32MDIChildWindow *Win32MDIClientWindow::getChildByID(INT id)
1214{
1215 Win32MDIChildWindow *child;
1216
1217 for (child = (Win32MDIChildWindow *)getFirstChild() ; child; child = (Win32MDIChildWindow *)child->getNextChild())
1218 if (child->getWindowId() == id) return child;
1219
1220 return 0;
1221}
1222
1223void Win32MDIClientWindow::postUpdate(WORD recalc)
1224{
1225 if( !(mdiFlags & MDIF_NEEDUPDATE) )
1226 {
1227 mdiFlags |= MDIF_NEEDUPDATE;
1228 PostMessageA(getWindowHandle(), WM_MDICALCCHILDSCROLL, 0, 0);
1229 }
1230 sbRecalc = recalc;
1231}
1232//******************************************************************************
1233//******************************************************************************
1234BOOL MDICLIENT_Register()
1235{
1236 WNDCLASSA wndClass;
1237
1238//SvL: Don't check this now
1239// if (GlobalFindAtomA(MDICLIENTCLASSNAMEA)) return FALSE;
1240
1241 ZeroMemory(&wndClass,sizeof(WNDCLASSA));
1242 wndClass.style = CS_GLOBALCLASS;
1243 wndClass.lpfnWndProc = (WNDPROC)MDIClientWndProc;
1244 wndClass.cbClsExtra = 0;
1245 wndClass.cbWndExtra = 0;
1246 wndClass.hCursor = 0;
1247 wndClass.hbrBackground = (HBRUSH)LTGRAY_BRUSH;
1248 wndClass.lpszClassName = MDICLIENTCLASSNAMEA;
1249
1250 return RegisterClassA(&wndClass);
1251}
1252//******************************************************************************
1253//******************************************************************************
1254BOOL MDICLIENT_Unregister()
1255{
1256 if (GlobalFindAtomA(MDICLIENTCLASSNAMEA))
1257 return UnregisterClassA(MDICLIENTCLASSNAMEA,(HINSTANCE)NULL);
1258 else return FALSE;
1259}
1260//******************************************************************************
1261//******************************************************************************
Note: See TracBrowser for help on using the repository browser.