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

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

merged with Corel WINE 20000212, added WS_EX_CONTEXTHELP

File size: 38.0 KB
Line 
1/* $Id: win32wmdiclient.cpp,v 1.25 2000-02-21 17:25:32 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#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 if( GetActiveWindow() == getParent()->getWindowHandle())
335 isActiveFrameWnd = TRUE;
336
337 /* deactivate prev. active child */
338 if( prevActive )
339 {
340 prevActive->setStyle(prevActive->getStyle() | WS_SYSMENU);
341 prevActive->SendInternalMessageA( WM_NCACTIVATE, FALSE, 0L );
342 prevActive->SendInternalMessageA( WM_MDIACTIVATE, (WPARAM)prevActive->getWindowHandle(), (LPARAM)(child) ? child->getWindowHandle() : 0);
343
344 /* uncheck menu item */
345 if( getMDIMenu() )
346 CheckMenuItem(getMDIMenu(), prevActive->getWindowId(), 0);
347 }
348
349 /* set appearance */
350 if( maximizedChild)
351 {
352 if( maximizedChild != child) {
353 if( child ) {
354 activeChild = child;
355 child->ShowWindow(SW_SHOWMAXIMIZED);
356 }
357 else
358 if(activeChild) activeChild->ShowWindow( SW_SHOWNORMAL );
359 }
360 }
361
362 dprintf(("childActivate: %x %x", this, (child) ? child->getWindowHandle() : 0));
363 activeChild = child;
364
365 /* check if we have any children left */
366 if( !activeChild )
367 {
368 if( isActiveFrameWnd )
369 SetFocus(getWindowHandle());
370
371 return 0;
372 }
373
374 /* check menu item */
375 if( getMDIMenu() )
376 CheckMenuItem(getMDIMenu(), child->getWindowId(), MF_CHECKED);
377
378 /* bring active child to the top */
379 child->SetWindowPos( 0,0,0,0,0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
380
381 if( isActiveFrameWnd )
382 {
383 child->SendInternalMessageA( WM_NCACTIVATE, TRUE, 0L);
384 if( GetFocus() == getWindowHandle())
385 SendInternalMessageA( WM_SETFOCUS, (WPARAM)getWindowHandle(), 0L );
386 else
387 SetFocus( getWindowHandle() );
388 }
389
390 /* @@@PH prevActive may be NULL actually ?! */
391 child->SendInternalMessageA( WM_MDIACTIVATE,
392 prevActive ? (WPARAM)prevActive->getWindowHandle() : 0,
393 child->getWindowHandle());
394 return TRUE;
395}
396/**********************************************************************
397 * MDI_SwitchActiveChild
398 *
399 * Note: SetWindowPos sends WM_CHILDACTIVATE to the child window that is
400 * being activated
401 */
402void Win32MDIClientWindow::switchActiveChild(Win32MDIChildWindow *nextActiveChild, BOOL bNextWindow )
403{
404 Win32MDIChildWindow *prevActiveChild = 0;
405
406 if ( !nextActiveChild) return; /* no window to switch to */
407
408 prevActiveChild = getActiveChild();
409
410 if ( prevActiveChild != nextActiveChild)
411 {
412 BOOL bOptimize = 0;
413
414 if( getMaximizedChild() )
415 {
416 bOptimize = 1;
417 nextActiveChild->setStyle(nextActiveChild->getStyle()& ~WS_VISIBLE);
418 }
419
420 nextActiveChild->SetWindowPos(HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
421
422 if( bNextWindow && prevActiveChild )
423 prevActiveChild->SetWindowPos(HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
424
425 if( bOptimize )
426 ShowWindow(SW_SHOW );
427 }
428}
429
430
431/**********************************************************************
432 * MDIDestroyChild
433 */
434LRESULT Win32MDIClientWindow::destroyChild(Win32MDIChildWindow *child, BOOL flagDestroy )
435{
436 if( child == getActiveChild())
437 {
438 switchActiveChild(child, TRUE);
439
440 if( child == getActiveChild() )
441 {
442 ::ShowWindow(child->getWindowHandle(),SW_HIDE);
443 if( child == getMaximizedChild() )
444 {
445 restoreFrameMenu(child);
446 setMaximizedChild(NULL);
447 updateFrameText(TRUE,NULL);
448 }
449 childActivate(0);
450 }
451 }
452 child->menuDeleteItem();
453
454 decNrActiveChildren();
455
456 dprintf(("child destroyed - %04x\n", child->getWindowHandle()));
457
458 if (flagDestroy)
459 {
460 postUpdate(SB_BOTH+1);
461 ::DestroyWindow(child->getWindowHandle());
462 }
463
464 return 0;
465}
466/**********************************************************************
467 * MDI_UpdateFrameText
468 *
469 * used when child window is maximized/restored
470 *
471 * Note: lpTitle can be NULL
472 */
473void Win32MDIClientWindow::updateFrameText(BOOL repaint, LPCSTR lpTitle )
474{
475 char lpBuffer[MDI_MAXTITLELENGTH+1];
476
477 /* store new "default" title if lpTitle is not NULL */
478 if (lpTitle)
479 {
480 if (frameTitle) HeapFree( GetProcessHeap(), 0, frameTitle );
481 frameTitle = HEAP_strdupA( GetProcessHeap(), 0, lpTitle );
482 }
483
484 if (frameTitle)
485 {
486 Win32MDIChildWindow *childWnd = getMaximizedChild();
487
488 if( childWnd && childWnd->getWindowNameA() )
489 {
490 /* combine frame title and child title if possible */
491
492 LPCSTR lpBracket = " - [";
493 int i_frame_text_length = strlen(frameTitle);
494 int i_child_text_length = strlen(childWnd->getWindowNameA());
495
496 lstrcpynA( lpBuffer, frameTitle, MDI_MAXTITLELENGTH);
497
498 if( i_frame_text_length + 6 < MDI_MAXTITLELENGTH )
499 {
500 strcat( lpBuffer, lpBracket );
501
502 if( i_frame_text_length + i_child_text_length + 6 < MDI_MAXTITLELENGTH )
503 {
504 strcat( lpBuffer, childWnd->getWindowNameA());
505 strcat( lpBuffer, "]" );
506 }
507 else
508 {
509 lstrcpynA(lpBuffer + i_frame_text_length + 4,
510 childWnd->getWindowNameA(), MDI_MAXTITLELENGTH - i_frame_text_length - 5 );
511 strcat( lpBuffer, "]" );
512 }
513 }
514 }
515 else
516 {
517 lstrcpynA(lpBuffer, frameTitle, MDI_MAXTITLELENGTH );
518 lpBuffer[MDI_MAXTITLELENGTH]='\0';
519 }
520 }
521 else
522 lpBuffer[0] = '\0';
523
524 getParent()->SetWindowTextA(lpBuffer);
525 if( repaint == MDI_REPAINTFRAME)
526 getParent()->SetWindowPos(0,0,0,0,0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
527}
528/**********************************************************************
529 * MDISetMenu
530 */
531LRESULT Win32MDIClientWindow::setMDIMenu(HMENU hmenuFrame, HMENU hmenuWindow)
532{
533 HWND hwndFrame = ::GetParent(getWindowHandle());
534 HMENU oldFrameMenu = ::GetMenu(hwndFrame);
535
536 if( maximizedChild && hmenuFrame && hmenuFrame!=oldFrameMenu )
537 restoreFrameMenu(maximizedChild);
538
539 if( hmenuWindow && hmenuWindow != hWindowMenu )
540 {
541 /* delete menu items from ci->hWindowMenu
542 * and add them to hmenuWindow */
543
544 INT i = GetMenuItemCount(hWindowMenu) - 1;
545 INT pos = GetMenuItemCount(hmenuWindow) + 1;
546
547 AppendMenuA( hmenuWindow, MF_SEPARATOR, 0, NULL);
548
549 if( nActiveChildren )
550 {
551 INT j = i - nActiveChildren + 1;
552 char buffer[100];
553 UINT id,state;
554
555 for( ; i >= j ; i-- )
556 {
557 id = GetMenuItemID(hWindowMenu,i );
558 state = GetMenuState(hWindowMenu,i,MF_BYPOSITION);
559
560 GetMenuStringA(hWindowMenu, i, buffer, 100, MF_BYPOSITION);
561
562 DeleteMenu(hWindowMenu, i , MF_BYPOSITION);
563 InsertMenuA(hmenuWindow, pos, MF_BYPOSITION | MF_STRING,
564 id, buffer);
565 CheckMenuItem(hmenuWindow ,pos , MF_BYPOSITION | (state & MF_CHECKED));
566 }
567 }
568
569 /* remove separator */
570 DeleteMenu(hWindowMenu, i, MF_BYPOSITION);
571
572 hWindowMenu = hmenuWindow;
573 }
574
575 if( hmenuFrame && hmenuFrame!=oldFrameMenu)
576 {
577 ::SetMenu(hwndFrame, hmenuFrame);
578
579 if (maximizedChild)
580 augmentFrameMenu(maximizedChild);
581
582 return oldFrameMenu;
583 }
584 return 0;
585}
586
587/**********************************************************************
588 * MDIRefreshMenu
589 */
590LRESULT Win32MDIClientWindow::refreshMDIMenu(HMENU hmenuFrame, HMENU hmenuWindow)
591{
592 HMENU oldFrameMenu = getParent()->GetMenu();
593
594// FIXME("partially function stub\n");
595
596 return oldFrameMenu;
597}
598/**********************************************************************
599 * MDI_RestoreFrameMenu
600 */
601BOOL Win32MDIClientWindow::restoreFrameMenu(Win32BaseWindow *child)
602{
603 MENUITEMINFOA menuInfo;
604 INT nItems = GetMenuItemCount(getParent()->GetMenu()) - 1;
605 UINT iId = GetMenuItemID(getParent()->GetMenu(),nItems) ;
606
607 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
608 return 0;
609
610 /*
611 * Remove the system menu, If that menu is the icon of the window
612 * as it is in win95, we have to delete the bitmap.
613 */
614 menuInfo.cbSize = sizeof(MENUITEMINFOA);
615 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
616
617 GetMenuItemInfoA(getParent()->GetMenu(),
618 0,
619 TRUE,
620 &menuInfo);
621
622 RemoveMenu(getParent()->GetMenu(),0,MF_BYPOSITION);
623
624//TODO: See augmentframemenu
625#if 0
626 if ((menuInfo.fType & MFT_BITMAP) &&
627 (LOWORD(menuInfo.dwTypeData)!=0) &&
628 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
629 {
630 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
631 }
632#endif
633
634 /* close */
635 DeleteMenu(getParent()->GetMenu(),GetMenuItemCount(getParent()->GetMenu()) - 1,MF_BYPOSITION);
636
637 /* restore */
638 DeleteMenu(getParent()->GetMenu(),GetMenuItemCount(getParent()->GetMenu()) - 1,MF_BYPOSITION);
639 /* minimize */
640 DeleteMenu(getParent()->GetMenu(),GetMenuItemCount(getParent()->GetMenu()) - 1,MF_BYPOSITION);
641
642 DrawMenuBar(getParent()->getWindowHandle());
643
644 return 1;
645}
646
647Win32BaseWindow** Win32MDIClientWindow::buildWindowArray(UINT bwaFlags,PUINT total)
648{
649 Win32BaseWindow **list = NULL,*win32wnd,**pos;
650 UINT skipHidden;
651 DWORD skipFlags;
652
653 skipHidden = bwaFlags & BWA_SKIPHIDDEN;
654 skipFlags = (bwaFlags & BWA_SKIPDISABLED) ? WS_DISABLED : 0;
655 if (bwaFlags & BWA_SKIPICONIC) skipFlags |= WS_MINIMIZE;
656
657 /* First count the windows */
658 *total = 0;
659 win32wnd = (Win32BaseWindow*)this->getFirstChild();
660 while (win32wnd)
661 {
662 if (!(win32wnd->getStyle() & skipFlags) && (!skipHidden || (win32wnd->getStyle() & WS_VISIBLE)))
663 (*total)++;
664 win32wnd = (Win32BaseWindow*)win32wnd->getNextChild();
665 }
666
667 if (*total)
668 {
669 /* Now build the list of all windows */
670 list = (Win32BaseWindow**)HeapAlloc(GetProcessHeap(),0,sizeof(Win32BaseWindow*)*(*total+1));
671 if (list)
672 {
673 for (win32wnd = (Win32BaseWindow*)this->getFirstChild(),pos = list;win32wnd;win32wnd = (Win32BaseWindow*)win32wnd->getNextChild())
674 {
675 if ((win32wnd->getStyle() & skipFlags));
676 else if(!skipHidden || win32wnd->getStyle() & WS_VISIBLE)
677 *pos++ = win32wnd;
678 }
679 *pos = NULL;
680 }
681 }
682
683 return list;
684}
685
686void Win32MDIClientWindow::releaseWindowArray(Win32BaseWindow **wndArray)
687{
688 HeapFree(GetProcessHeap(),0,wndArray);
689}
690
691/**********************************************************************
692 * MDI_CalcDefaultChildPos
693 *
694 * It seems that the default height is about 2/3 of the client rect
695 */
696void Win32MDIClientWindow::calcDefaultChildPos(WORD n,LPPOINT lpPos,INT delta)
697{
698 INT nstagger;
699 RECT rect;
700 INT spacing = GetSystemMetrics(SM_CYCAPTION) +
701 GetSystemMetrics(SM_CYFRAME) - 1;
702
703 getClientRect(&rect);
704 if( rect.bottom - rect.top - delta >= spacing )
705 rect.bottom -= delta;
706
707 nstagger = (rect.bottom - rect.top)/(3 * spacing);
708 lpPos[1].x = (rect.right - rect.left - nstagger * spacing);
709 lpPos[1].y = (rect.bottom - rect.top - nstagger * spacing);
710 lpPos[0].x = lpPos[0].y = spacing * (n%(nstagger+1));
711}
712
713/**********************************************************************
714 * MDICascade
715 */
716BOOL Win32MDIClientWindow::cascade(UINT fuCascade)
717{
718 Win32BaseWindow **list;
719 UINT total = 0;
720
721 if (getMaximizedChild())
722 SendInternalMessageA(WM_MDIRESTORE, (WPARAM)getMaximizedChild()->getWindowHandle(), 0);
723
724 if (nActiveChildren == 0) return 0;
725
726 list = buildWindowArray(BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC,&total);
727 if (list)
728 {
729 Win32BaseWindow** heapPtr = list;
730 if (total)
731 {
732 INT delta = 0,n = 0;
733 POINT pos[2];
734
735
736 if (total < nActiveChildren)
737 delta = GetSystemMetrics(SM_CYICONSPACING)+GetSystemMetrics(SM_CYICON);
738
739 // walk the list (backwards) and move windows
740 while (*list) list++;
741 while (list != heapPtr)
742 {
743 list--;
744
745 calcDefaultChildPos(n++,pos,delta);
746 ::SetWindowPos((*list)->getWindowHandle(),0,pos[0].x,pos[0].y,pos[1].x,pos[1].y,SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
747 }
748 }
749 releaseWindowArray(heapPtr);
750 }
751
752 if (total < nActiveChildren)
753 ArrangeIconicWindows(Win32Hwnd);
754
755 return TRUE;
756}
757
758/**********************************************************************
759 * MDITile
760 */
761BOOL Win32MDIClientWindow::tile(UINT fuTile)
762{
763 Win32BaseWindow** list;
764 UINT total = 0;
765
766 if (getMaximizedChild())
767 SendInternalMessageA(WM_MDIRESTORE, (WPARAM)getMaximizedChild()->getWindowHandle(), 0);
768
769 if (nActiveChildren == 0) return TRUE;
770
771 list = buildWindowArray(BWA_SKIPHIDDEN | BWA_SKIPOWNED | BWA_SKIPICONIC |
772 ((fuTile & MDITILE_SKIPDISABLED)? BWA_SKIPDISABLED : 0), &total );
773
774 if (list)
775 {
776 Win32BaseWindow** heapPtr = list;
777
778 if (total)
779 {
780 RECT rect;
781 int x, y, xsize, ysize;
782 int rows, columns, r, c, i;
783
784 GetClientRect(Win32Hwnd,&rect);
785 rows = (int) sqrt((double)total);
786 columns = total / rows;
787
788 if( fuTile & MDITILE_HORIZONTAL ) // version >= 3.1
789 {
790 i = rows;
791 rows = columns; // exchange r and c
792 columns = i;
793 }
794
795 if( total != nActiveChildren)
796 {
797 y = rect.bottom - 2 * GetSystemMetrics(SM_CYICONSPACING) - GetSystemMetrics(SM_CYICON);
798 rect.bottom = ( y - GetSystemMetrics(SM_CYICON) < rect.top )? rect.bottom: y;
799 }
800
801 ysize = rect.bottom / rows;
802 xsize = rect.right / columns;
803
804 for (x = i = 0, c = 1; c <= columns && *list; c++)
805 {
806 if (c == columns)
807 {
808 rows = total - i;
809 ysize = rect.bottom / rows;
810 }
811
812 y = 0;
813 for (r = 1; r <= rows && *list; r++, i++)
814 {
815 ::SetWindowPos((*list)->getWindowHandle(), 0, x, y, xsize, ysize,
816 SWP_DRAWFRAME | SWP_NOACTIVATE | SWP_NOZORDER);
817 y += ysize;
818 list++;
819 }
820 x += xsize;
821 }
822 }
823 releaseWindowArray(heapPtr);
824 }
825
826 if( total < nActiveChildren ) ArrangeIconicWindows(Win32Hwnd);
827
828 return TRUE;
829}
830
831/* ----------------------- Frame window ---------------------------- */
832
833/**********************************************************************
834 * MDI_AugmentFrameMenu
835 */
836BOOL Win32MDIClientWindow::augmentFrameMenu(Win32MDIChildWindow *child)
837{
838 HMENU hSysPopup = 0,hFrameMenu = ::GetMenu(getParent()->getWindowHandle()),hSysMenu = ::GetSystemMenu(child->getWindowHandle(),FALSE);
839 HBITMAP hSysMenuBitmap = 0;
840
841 if (!hFrameMenu || !hSysMenu)
842 return 0;
843
844 // create a copy of sysmenu popup and insert it into frame menu bar
845
846 if (!(hSysPopup = LoadMenuA(GetModuleHandleA("USER32"), "SYSMENU")))
847 return 0;
848
849 //TRACE("\tgot popup %04x in sysmenu %04x\n",
850 // hSysPopup, child->hSysMenu);
851
852 AppendMenuA(hFrameMenu,MF_HELP | MF_BITMAP,
853 SC_MINIMIZE, (LPSTR)(DWORD)HBMMENU_MBAR_MINIMIZE ) ;
854 AppendMenuA(hFrameMenu,MF_HELP | MF_BITMAP,
855 SC_RESTORE, (LPSTR)(DWORD)HBMMENU_MBAR_RESTORE );
856
857 // In Win 95 look, the system menu is replaced by the child icon
858
859 /* Find small icon */
860 HICON hIcon = child->GetSmallIcon();
861
862 /* If no small icon or overwridden large icon, use class small icon.. */
863 if (!hIcon && !child->GetIcon())
864 hIcon = GetClassLongA(child->getWindowHandle(),GCL_HICONSM);
865
866 /* Use large icon */
867 if (!hIcon) hIcon = child->GetIcon();
868
869 /* If all else fails, use large class icon. */
870 if (!hIcon) hIcon = GetClassLongA(child->getWindowHandle(),GCL_HICON);
871
872 if (hIcon)
873 {
874 HDC hMemDC;
875 HBITMAP hBitmap, hOldBitmap;
876 HBRUSH hBrush;
877 HDC hdc = GetDC(child->getWindowHandle());
878
879 if (hdc)
880 {
881 int cx, cy;
882
883 cx = GetSystemMetrics(SM_CXSMICON);
884 cy = GetSystemMetrics(SM_CYSMICON);
885 hMemDC = CreateCompatibleDC(hdc);
886 hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
887 hOldBitmap = SelectObject(hMemDC, hBitmap);
888 SetMapMode(hMemDC, MM_TEXT);
889 hBrush = CreateSolidBrush(GetSysColor(COLOR_MENU));
890 DrawIconEx(hMemDC, 0, 0, hIcon, cx, cy, 0, hBrush, DI_NORMAL);
891 SelectObject (hMemDC, hOldBitmap);
892 DeleteObject(hBrush);
893 DeleteDC(hMemDC);
894 ReleaseDC(child->getWindowHandle(), hdc);
895 hSysMenuBitmap = hBitmap;
896 }
897 }
898
899 if( !InsertMenuA(hFrameMenu,0,MF_BYPOSITION | MF_BITMAP | MF_POPUP,
900 hSysPopup, (LPSTR)(DWORD)hSysMenuBitmap))
901 {
902 //TRACE("not inserted\n");
903 DestroyMenu(hSysPopup);
904 return 0;
905 }
906
907 // The close button is only present in Win 95 look
908
909 AppendMenuA(hFrameMenu,MF_HELP | MF_BITMAP,
910 SC_CLOSE, (LPSTR)(DWORD)HBMMENU_MBAR_CLOSE );
911
912 EnableMenuItem(hSysPopup, SC_SIZE, MF_BYCOMMAND | MF_GRAYED);
913 EnableMenuItem(hSysPopup, SC_MOVE, MF_BYCOMMAND | MF_GRAYED);
914 EnableMenuItem(hSysPopup, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
915 SetMenuDefaultItem(hSysPopup, SC_CLOSE, FALSE);
916
917 // redraw menu
918 DrawMenuBar(getParent()->getWindowHandle());
919
920 return 1;
921}
922
923/**********************************************************************
924 * MDI_RestoreFrameMenu
925 */
926BOOL Win32MDIClientWindow::restoreFrameMenu(Win32MDIChildWindow *child)
927{
928 MENUITEMINFOA menuInfo;
929 HMENU hFrameMenu = ::GetMenu(getParent()->getWindowHandle());
930 INT nItems = GetMenuItemCount(hFrameMenu) - 1;
931 UINT iId = GetMenuItemID(hFrameMenu,nItems) ;
932
933 //TRACE("frameWnd %p,child %04x\n",frameWnd,hChild);
934
935 if(!(iId == SC_RESTORE || iId == SC_CLOSE) )
936 return 0;
937
938 /*
939 * Remove the system menu, If that menu is the icon of the window
940 * as it is in win95, we have to delete the bitmap.
941 */
942
943 menuInfo.cbSize = sizeof(MENUITEMINFOA);
944 menuInfo.fMask = MIIM_DATA | MIIM_TYPE;
945
946 GetMenuItemInfoA(hFrameMenu,
947 0,
948 TRUE,
949 &menuInfo);
950
951 RemoveMenu(hFrameMenu,0,MF_BYPOSITION);
952
953#if 0 //CB: hBmpClose not (yet) defined
954 if ( (menuInfo.fType & MFT_BITMAP) &&
955 (LOWORD(menuInfo.dwTypeData)!=0) &&
956 (LOWORD(menuInfo.dwTypeData)!=hBmpClose) )
957 {
958 DeleteObject((HBITMAP)LOWORD(menuInfo.dwTypeData));
959 }
960#endif
961
962 // close
963 DeleteMenu(hFrameMenu,GetMenuItemCount(hFrameMenu) - 1,MF_BYPOSITION);
964
965 // restore
966 DeleteMenu(hFrameMenu,GetMenuItemCount(hFrameMenu) - 1,MF_BYPOSITION);
967 // minimize
968 DeleteMenu(hFrameMenu,GetMenuItemCount(hFrameMenu) - 1,MF_BYPOSITION);
969
970 DrawMenuBar(getParent()->getWindowHandle());
971
972 return 1;
973}
974
975/***********************************************************************
976 * CalcChildScroll (USER.462)
977 */
978void WINAPI CalcChildScroll(HWND hwnd,WORD scroll)
979{
980 Win32BaseWindow *win32wnd = Win32BaseWindow::GetWindowFromHandle(hwnd);
981 SCROLLINFO info;
982 RECT childRect, clientRect;
983 INT vmin, vmax, hmin, hmax, vpos, hpos;
984
985 if (!win32wnd) return;
986
987 GetClientRect( hwnd, &clientRect );
988 SetRectEmpty( &childRect );
989
990 for (win32wnd = (Win32BaseWindow*)win32wnd->getFirstChild();win32wnd;win32wnd = (Win32BaseWindow*)win32wnd->getNextChild())
991 {
992 if( win32wnd->getStyle() & WS_MAXIMIZE )
993 {
994 ShowScrollBar(hwnd, SB_BOTH, FALSE);
995 return;
996 }
997 UnionRect(&childRect,win32wnd->getWindowRect(),&childRect);
998 }
999 UnionRect( &childRect, &clientRect, &childRect );
1000
1001 hmin = childRect.left; hmax = childRect.right - clientRect.right;
1002 hpos = clientRect.left - childRect.left;
1003 vmin = childRect.top; vmax = childRect.bottom - clientRect.bottom;
1004 vpos = clientRect.top - childRect.top;
1005
1006 switch( scroll )
1007 {
1008 case SB_HORZ:
1009 vpos = hpos; vmin = hmin; vmax = hmax;
1010 case SB_VERT:
1011 info.cbSize = sizeof(info);
1012 info.nMax = vmax; info.nMin = vmin; info.nPos = vpos;
1013 info.fMask = SIF_POS | SIF_RANGE;
1014 SetScrollInfo(hwnd, scroll, &info, TRUE);
1015 break;
1016 case SB_BOTH:
1017 {
1018 SCROLLINFO vInfo, hInfo;
1019
1020 vInfo.cbSize = hInfo.cbSize = sizeof(SCROLLINFO);
1021 vInfo.nMin = vmin;
1022 hInfo.nMin = hmin;
1023 vInfo.nMax = vmax;
1024 hInfo.nMax = hmax;
1025 vInfo.nPos = vpos;
1026 hInfo.nPos = hpos;
1027 vInfo.fMask = hInfo.fMask = SIF_RANGE | SIF_POS;
1028
1029 SetScrollInfo(hwnd,SB_VERT,&vInfo,TRUE);
1030 SetScrollInfo(hwnd,SB_HORZ,&hInfo,TRUE);
1031 }
1032 }
1033}
1034
1035/***********************************************************************
1036 * ScrollChildren32 (USER32.448)
1037 */
1038void WINAPI ScrollChildren(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
1039{
1040 Win32BaseWindow *win32wnd = Win32BaseWindow::GetWindowFromHandle(hWnd);
1041 INT newPos = -1;
1042 INT curPos, length, minPos, maxPos, shift;
1043
1044 if (!win32wnd) return;
1045
1046 if (uMsg == WM_HSCROLL)
1047 {
1048 GetScrollRange(hWnd,SB_HORZ,&minPos,&maxPos);
1049 curPos = GetScrollPos(hWnd,SB_HORZ);
1050 length = win32wnd->getClientWidth()/2;
1051 shift = GetSystemMetrics(SM_CYHSCROLL);
1052 } else if (uMsg == WM_VSCROLL)
1053 {
1054 GetScrollRange(hWnd,SB_VERT,&minPos,&maxPos);
1055 curPos = GetScrollPos(hWnd,SB_VERT);
1056 length = win32wnd->getClientHeight()/2;
1057 shift = GetSystemMetrics(SM_CXVSCROLL);
1058 } else return;
1059
1060 switch( wParam )
1061 {
1062 case SB_LINEUP:
1063 newPos = curPos - shift;
1064 break;
1065
1066 case SB_LINEDOWN:
1067 newPos = curPos + shift;
1068 break;
1069
1070 case SB_PAGEUP:
1071 newPos = curPos - length;
1072 break;
1073
1074 case SB_PAGEDOWN:
1075 newPos = curPos + length;
1076 break;
1077
1078 case SB_THUMBPOSITION:
1079 newPos = LOWORD(lParam);
1080 break;
1081
1082 case SB_THUMBTRACK:
1083 return;
1084
1085 case SB_TOP:
1086 newPos = minPos;
1087 break;
1088
1089 case SB_BOTTOM:
1090 newPos = maxPos;
1091 break;
1092
1093 case SB_ENDSCROLL:
1094 CalcChildScroll(hWnd,(uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ);
1095 return;
1096 }
1097
1098 if( newPos > maxPos )
1099 newPos = maxPos;
1100 else
1101 if( newPos < minPos )
1102 newPos = minPos;
1103
1104 SetScrollPos(hWnd, (uMsg == WM_VSCROLL)?SB_VERT:SB_HORZ , newPos, TRUE);
1105
1106 if( uMsg == WM_VSCROLL )
1107 ScrollWindowEx(hWnd ,0 ,curPos - newPos, NULL, NULL, 0, NULL,
1108 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1109 else
1110 ScrollWindowEx(hWnd ,curPos - newPos, 0, NULL, NULL, 0, NULL,
1111 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1112}
1113
1114/*****************************************************************************
1115 * Name : WORD WIN32API CascadeWindows
1116 * Purpose : The CascadeWindows function cascades the specified windows or
1117 * the child windows of the specified parent window.
1118 * Parameters: HWND hwndParent handle of parent window
1119 * UINT wHow types of windows not to arrange
1120 * CONST RECT * lpRect rectangle to arrange windows in
1121 * UINT cKids number of windows to arrange
1122 * const HWND FAR * lpKids array of window handles
1123 * Variables :
1124 * Result : If the function succeeds, the return value is the number of windows arranged.
1125 * If the function fails, the return value is zero.
1126 * Remark :
1127 * Status : UNTESTED STUB
1128 *
1129 * Author : Patrick Haller [Thu, 1998/02/26 11:55]
1130 *****************************************************************************/
1131WORD WIN32API CascadeWindows(HWND hwndParent,
1132 UINT wHow,
1133 CONST LPRECT lpRect,
1134 UINT cKids,
1135 const HWND *lpKids)
1136{
1137 dprintf(("USER32:CascadeWindows(%08xh,%u,%08xh,%u,%08x) not implemented.\n",
1138 hwndParent,
1139 wHow,
1140 lpRect,
1141 cKids,
1142 lpKids));
1143
1144 return (0);
1145}
1146
1147/*****************************************************************************
1148 * Name : BOOL WIN32API CascadeChildWindows
1149 * Purpose : Unknown
1150 * Parameters: Unknown
1151 * Variables :
1152 * Result :
1153 * Remark :
1154 * Status : UNTESTED UNKNOWN STUB
1155 *
1156 * Author : Patrick Haller [Wed, 1998/06/16 11:55]
1157 *****************************************************************************/
1158BOOL WIN32API CascadeChildWindows(DWORD x1,
1159 DWORD x2)
1160{
1161 dprintf(("USER32: CascadeChildWindows(%08xh,%08xh) not implemented.\n",
1162 x1,
1163 x2));
1164
1165 return (FALSE); /* default */
1166}
1167
1168/*****************************************************************************
1169 * Name : WORD WIN32API TileWindows
1170 * Purpose : The TileWindows function tiles the specified windows, or the child
1171 * windows of the specified parent window.
1172 * Parameters: HWND hwndParent handle of parent window
1173 * WORD wFlags types of windows not to arrange
1174 * LPCRECT lpRect rectangle to arrange windows in
1175 * WORD cChildrenb number of windows to arrange
1176 * const HWND *ahwndChildren array of window handles
1177 * Variables :
1178 * Result : If the function succeeds, the return value is the number of
1179 * windows arranged.
1180 * If the function fails, the return value is zero.
1181 * Remark :
1182 * Status : UNTESTED STUB
1183 *
1184 * Author : Patrick Haller [Thu, 1998/02/26 11:55]
1185 *****************************************************************************/
1186WORD WIN32API TileWindows(HWND hwndParent,
1187 UINT wFlags,
1188 const LPRECT lpRect,
1189 UINT cChildrenb,
1190 const HWND *ahwndChildren)
1191{
1192 dprintf(("USER32:TileWindows (%08xh,%08xh,%08xh,%08xh,%08x) not implemented.\n",
1193 hwndParent,
1194 wFlags,
1195 lpRect,
1196 cChildrenb,
1197 ahwndChildren));
1198
1199 return (0);
1200}
1201
1202/*****************************************************************************
1203 * Name : BOOL WIN32API TileChildWindows
1204 * Purpose : Unknown
1205 * Parameters: Unknown
1206 * Variables :
1207 * Result :
1208 * Remark :
1209 * Status : UNTESTED UNKNOWN STUB
1210 *
1211 * Author : Patrick Haller [Wed, 1998/06/16 11:55]
1212 *****************************************************************************/
1213BOOL WIN32API TileChildWindows(DWORD x1,
1214 DWORD x2)
1215{
1216 dprintf(("USER32: TileChildWindows(%08xh,%08xh) not implemented.\n",
1217 x1,
1218 x2));
1219
1220 return (FALSE); /* default */
1221}
1222
1223/* -------- Miscellaneous service functions ----------
1224 *
1225 * MDI_GetChildByID
1226 */
1227Win32MDIChildWindow *Win32MDIClientWindow::getChildByID(INT id)
1228{
1229 Win32MDIChildWindow *child;
1230
1231 for (child = (Win32MDIChildWindow *)getFirstChild() ; child; child = (Win32MDIChildWindow *)child->getNextChild())
1232 if (child->getWindowId() == id) return child;
1233
1234 return 0;
1235}
1236
1237void Win32MDIClientWindow::postUpdate(WORD recalc)
1238{
1239 if( !(mdiFlags & MDIF_NEEDUPDATE) )
1240 {
1241 mdiFlags |= MDIF_NEEDUPDATE;
1242 PostMessageA(getWindowHandle(), WM_MDICALCCHILDSCROLL, 0, 0);
1243 }
1244 sbRecalc = recalc;
1245}
1246//******************************************************************************
1247//******************************************************************************
1248BOOL MDICLIENT_Register()
1249{
1250 WNDCLASSA wndClass;
1251
1252//SvL: Don't check this now
1253// if (GlobalFindAtomA(MDICLIENTCLASSNAMEA)) return FALSE;
1254
1255 ZeroMemory(&wndClass,sizeof(WNDCLASSA));
1256 wndClass.style = CS_GLOBALCLASS;
1257 wndClass.lpfnWndProc = (WNDPROC)MDIClientWndProc;
1258 wndClass.cbClsExtra = 0;
1259 wndClass.cbWndExtra = 0;
1260 wndClass.hCursor = 0;
1261 wndClass.hbrBackground = (HBRUSH)LTGRAY_BRUSH;
1262 wndClass.lpszClassName = MDICLIENTCLASSNAMEA;
1263
1264 return RegisterClassA(&wndClass);
1265}
1266//******************************************************************************
1267//******************************************************************************
1268BOOL MDICLIENT_Unregister()
1269{
1270 if (GlobalFindAtomA(MDICLIENTCLASSNAMEA))
1271 return UnregisterClassA(MDICLIENTCLASSNAMEA,(HINSTANCE)NULL);
1272 else return FALSE;
1273}
1274//******************************************************************************
1275//******************************************************************************
Note: See TracBrowser for help on using the repository browser.