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

Last change on this file since 3153 was 3153, checked in by cbratschi, 25 years ago

merged with Corel 20000317, small icon

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