]> git.saurik.com Git - wxWidgets.git/blob - src/msw/mdi.cpp
Cured problem introduced by LEAVE/ENTER OnIdle code; bugs in gauge sizing
[wxWidgets.git] / src / msw / mdi.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mdi.cpp
3 // Purpose: MDI classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "mdi.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/setup.h"
25 #include "wx/frame.h"
26 #include "wx/menu.h"
27 #include "wx/app.h"
28 #include "wx/utils.h"
29 #include "wx/dialog.h"
30 #include "wx/statusbr.h"
31 #include "wx/settings.h"
32 #endif
33
34 #include "wx/mdi.h"
35 #include "wx/msw/private.h"
36
37 #if USE_NATIVE_STATUSBAR
38 #include <wx/msw/statbr95.h>
39 #endif
40
41 #include <string.h>
42
43 extern wxList wxModelessWindows;
44
45 #define IDM_WINDOWTILE 4001
46 #define IDM_WINDOWCASCADE 4002
47 #define IDM_WINDOWICONS 4003
48 #define IDM_WINDOWNEXT 4004
49 // This range gives a maximum of 500
50 // MDI children. Should be enough :-)
51 #define wxFIRST_MDI_CHILD 4100
52 #define wxLAST_MDI_CHILD 4600
53
54 // Status border dimensions
55 #define wxTHICK_LINE_BORDER 3
56 #define wxTHICK_LINE_WIDTH 1
57
58 extern char wxMDIFrameClassName[];
59 extern char wxMDIChildFrameClassName[];
60 extern wxWindow *wxWndHook;
61
62 #if !USE_SHARED_LIBRARY
63 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame)
64 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame)
65 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow)
66
67 BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
68 EVT_SIZE(wxMDIParentFrame::OnSize)
69 EVT_ACTIVATE(wxMDIParentFrame::OnActivate)
70 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged)
71 END_EVENT_TABLE()
72
73 BEGIN_EVENT_TABLE(wxMDIClientWindow, wxWindow)
74 EVT_SCROLL(wxMDIClientWindow::OnScroll)
75 END_EVENT_TABLE()
76
77 #endif
78
79 wxMDIParentFrame::wxMDIParentFrame(void)
80 {
81 m_clientWindow = NULL;
82 m_currentChild = NULL;
83 m_windowMenu = 0;
84 m_parentFrameActive = TRUE;
85 m_frameToolBar = NULL ;
86 }
87
88 bool wxMDIParentFrame::Create(wxWindow *parent,
89 const wxWindowID id,
90 const wxString& title,
91 const wxPoint& pos,
92 const wxSize& size,
93 const long style,
94 const wxString& name)
95 {
96 m_defaultIcon = (WXHICON) (wxSTD_MDIPARENTFRAME_ICON ? wxSTD_MDIPARENTFRAME_ICON : wxDEFAULT_MDIPARENTFRAME_ICON);
97
98 m_frameToolBar = NULL ;
99 m_clientWindow = NULL;
100 m_currentChild = NULL;
101 m_windowMenu = 0;
102 m_parentFrameActive = TRUE;
103
104 if (!parent)
105 wxTopLevelWindows.Append(this);
106
107 SetName(name);
108 m_windowStyle = style;
109
110 if (parent) parent->AddChild(this);
111
112 if ( id > -1 )
113 m_windowId = id;
114 else
115 m_windowId = (int)NewControlId();
116
117 int x = pos.x;
118 int y = pos.y;
119 int width = size.x;
120 int height = size.y;
121
122 m_windowMenu = (WXHMENU) ::LoadMenu(wxGetInstance(), "wxWindowMenu");
123
124 #if DEBUG > 1
125 wxDebugMsg("Loaded m_windowMenu %d\n", m_windowMenu);
126 #endif
127
128 // Adding WS_CLIPCHILDREN causes children not to be properly
129 // drawn when first displaying them.
130 DWORD msflags = WS_OVERLAPPED ; // | WS_CLIPCHILDREN ;
131 if (style & wxMINIMIZE_BOX)
132 msflags |= WS_MINIMIZEBOX;
133 if (style & wxMAXIMIZE_BOX)
134 msflags |= WS_MAXIMIZEBOX;
135 if (style & wxTHICK_FRAME)
136 msflags |= WS_THICKFRAME;
137 if (style & wxSYSTEM_MENU)
138 msflags |= WS_SYSMENU;
139 if ((style & wxMINIMIZE) || (style & wxICONIZE))
140 msflags |= WS_MINIMIZE;
141 if (style & wxMAXIMIZE)
142 msflags |= WS_MAXIMIZE;
143 if (style & wxCAPTION)
144 msflags |= WS_CAPTION;
145 if (style & wxCLIP_CHILDREN)
146 msflags |= WS_CLIPCHILDREN;
147
148 wxWindow::MSWCreate(m_windowId, parent, wxMDIFrameClassName, this, title, x, y, width, height,
149 msflags);
150
151 wxModelessWindows.Append(this);
152
153 return TRUE;
154 }
155
156 wxMDIParentFrame::~wxMDIParentFrame(void)
157 {
158 DestroyChildren();
159
160 DestroyMenu((HMENU) m_windowMenu); // Destroy dummy "Window" menu
161 m_windowMenu = 0;
162
163 if (m_clientWindow->MSWGetOldWndProc())
164 m_clientWindow->UnsubclassWin();
165
166 m_clientWindow->m_hWnd = 0;
167 delete m_clientWindow;
168 }
169
170 // Get size *available for subwindows* i.e. excluding menu bar.
171 void wxMDIParentFrame::GetClientSize(int *x, int *y) const
172 {
173 RECT rect;
174 GetClientRect((HWND) GetHWND(), &rect);
175
176 int cwidth = rect.right;
177 int cheight = rect.bottom;
178 /*
179 if (m_frameToolBar)
180 {
181 int tw, th;
182 m_frameToolBar->GetSize(&tw, &th);
183 cheight -= th;
184 }
185 */
186 if ( GetStatusBar() )
187 {
188 int sw, sh;
189 GetStatusBar()->GetSize(&sw, &sh);
190 cheight -= sh;
191 }
192
193 *x = cwidth;
194 *y = cheight;
195 }
196
197 void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar)
198 {
199 if (!menu_bar)
200 {
201 m_frameMenuBar = NULL;
202 return;
203 }
204
205 if (menu_bar->m_menuBarFrame)
206 return;
207
208 int i;
209 HMENU menu = CreateMenu();
210
211 for (i = 0; i < menu_bar->m_menuCount; i ++)
212 {
213 HMENU popup = (HMENU)menu_bar->m_menus[i]->m_hMenu;
214 //
215 // After looking Bounds Checker result, it seems that all
216 // menus must be individually destroyed. So, don't reset m_hMenu,
217 // to allow ~wxMenu to do the job.
218 //
219 menu_bar->m_menus[i]->m_savehMenu = (WXHMENU) popup;
220 // Uncommenting for the moment... JACS
221 menu_bar->m_menus[i]->m_hMenu = (WXHMENU) NULL;
222 AppendMenu(menu, MF_POPUP | MF_STRING, (UINT)popup, menu_bar->m_titles[i]);
223 }
224
225 menu_bar->m_hMenu = (WXHMENU)menu;
226 if (m_frameMenuBar)
227 delete m_frameMenuBar;
228
229 this->m_hMenu = (WXHMENU) menu;
230
231 // MDI parent-specific code follows
232
233 HMENU subMenu = GetSubMenu((HMENU) m_windowMenu, 0);
234
235 // Try to insert Window menu in front of Help, otherwise append it.
236 int N = GetMenuItemCount(menu);
237 bool success = FALSE;
238 for (i = 0; i < N; i++)
239 {
240 char buf[100];
241 int chars = GetMenuString(menu, i, buf, 100, MF_BYPOSITION);
242 if ((chars > 0) && (strcmp(buf, "&Help") == 0 ||
243 strcmp(buf, "Help") == 0))
244 {
245 success = TRUE;
246 InsertMenu(menu, i, MF_BYPOSITION | MF_POPUP | MF_STRING,
247 (UINT)subMenu, "&Window");
248 break;
249 }
250 }
251 if (!success)
252 AppendMenu(menu, MF_POPUP,
253 (UINT)subMenu,
254 "&Window");
255 m_parentFrameActive = TRUE;
256 #ifdef __WIN32__
257 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDISETMENU,
258 (WPARAM)menu,
259 (LPARAM)subMenu);
260 #else
261 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
262 MAKELPARAM(menu, subMenu));
263 #endif
264 DrawMenuBar((HWND) GetHWND());
265
266 m_frameMenuBar = menu_bar;
267 menu_bar->m_menuBarFrame = this;
268 }
269
270 void wxMDIParentFrame::OnSize(wxSizeEvent& event)
271 {
272 #if USE_CONSTRAINTS
273 if (GetAutoLayout())
274 Layout();
275 #endif
276 int x = 0;
277 int y = 0;
278 int width, height;
279 GetClientSize(&width, &height);
280 if ( GetToolBar() )
281 {
282 int wt, ht;
283 GetToolBar()->GetSize(&wt, &ht);
284 height -= ht;
285 y += ht;
286 GetToolBar()->SetSize(0, 0, width, ht);
287 }
288
289 if ( GetClientWindow() )
290 GetClientWindow()->SetSize(x, y, width, height);
291
292 // forward WM_SIZE to status bar control
293 #if USE_NATIVE_STATUSBAR
294 if (m_frameStatusBar && m_frameStatusBar->IsKindOf(CLASSINFO(wxStatusBar95)))
295 ((wxStatusBar95 *)m_frameStatusBar)->OnSize(event);
296 #endif
297 }
298
299 void wxMDIParentFrame::OnActivate(wxActivateEvent& event)
300 {
301 // Do nothing
302 }
303
304 #if WXWIN_COMPATIBILITY
305 void wxMDIParentFrame::OldOnSize(int x, int y)
306 {
307 #if WXWIN_COMPATIBILITY == 1
308 wxSizeEvent event(wxSize(x, y), m_windowId);
309 event.SetEventObject( this );
310 GetEventHandler()->ProcessEvent(event);
311 #else
312
313 #if USE_CONSTRAINTS
314 if (GetAutoLayout())
315 Layout();
316 #endif
317 int x = 0;
318 int y = 0;
319 int width, height;
320 GetClientSize(&width, &height);
321 if ( GetToolBar() )
322 {
323 int wt, ht;
324 GetToolBar()->GetSize(&wt, &ht);
325 height -= ht;
326 y += ht;
327 }
328
329 if ( GetClientWindow() )
330 GetClientWindow()->SetSize(x, y, width, height);
331
332 #endif
333 }
334
335 // Default activation behaviour - nothing.
336 // Default activation behaviour - override dedault wxFrame behaviour
337 void wxMDIParentFrame::OldOnActivate(bool flag)
338 {
339 #if WXWIN_COMPATIBILITY == 1
340 wxActivateEvent event(wxEVT_ACTIVATE, flag, m_windowId);
341 event.SetEventObject( this );
342 GetEventHandler()->ProcessEvent(event);
343 #else
344 #endif
345 }
346
347 #endif
348
349 // Returns the active MDI child window
350 wxMDIChildFrame *wxMDIParentFrame::GetActiveChild(void) const
351 {
352 // HWND hWnd = (HWND)LOWORD(SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIGETACTIVE, 0, 0L));
353 HWND hWnd = (HWND)SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIGETACTIVE, 0, 0L);
354 if (hWnd == 0)
355 return NULL;
356 else
357 return (wxMDIChildFrame *)wxFindWinFromHandle((WXHWND) hWnd);
358 }
359
360 // Create the client window class (don't Create the window,
361 // just return a new class)
362 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient(void)
363 {
364 return new wxMDIClientWindow ;
365 }
366
367 // Responds to colour changes, and passes event on to children.
368 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
369 {
370 if ( m_clientWindow )
371 {
372 m_clientWindow->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE));
373 m_clientWindow->Refresh();
374 }
375 /*
376 if ( m_frameToolBar )
377 {
378 wxSysColourChangedEvent event2;
379 event2.eventObject = m_frameToolBar;
380 m_frameToolBar->GetEventHandler()->ProcessEvent(event2);
381 }
382 */
383
384 // Propagate the event to the non-top-level children
385 wxFrame::OnSysColourChanged(event);
386 }
387
388 // MDI operations
389 void wxMDIParentFrame::Cascade(void)
390 {
391 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDICASCADE, 0, 0);
392 }
393
394 void wxMDIParentFrame::Tile(void)
395 {
396 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDITILE, MDITILE_HORIZONTAL, 0);
397 }
398
399 void wxMDIParentFrame::ArrangeIcons(void)
400 {
401 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDIICONARRANGE, 0, 0);
402 }
403
404 void wxMDIParentFrame::ActivateNext(void)
405 {
406 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 0);
407 }
408
409 void wxMDIParentFrame::ActivatePrevious(void)
410 {
411 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 1);
412 }
413
414
415 /*
416 // Returns a style for the client window - usually 0
417 // or, for example, wxHSCROLL | wxVSCROLL
418 long wxMDIParentFrame::GetClientStyle(void) const
419 {
420 return wxHSCROLL | wxVSCROLL ;
421 }
422 */
423
424 bool wxMDIParentFrame::MSWOnDestroy(void)
425 {
426 return FALSE;
427 }
428
429 void wxMDIParentFrame::MSWOnCreate(WXLPCREATESTRUCT WXUNUSED(cs))
430 {
431 m_clientWindow = new wxMDIClientWindow;
432 // Uses own style for client style
433 m_clientWindow->CreateClient(this, GetWindowStyleFlag());
434 }
435
436 void wxMDIParentFrame::MSWOnSize(const int x, const int y, const WXUINT id)
437 {
438 switch (id)
439 {
440 case SIZEFULLSCREEN:
441 case SIZENORMAL:
442 m_iconized = FALSE;
443 break;
444 case SIZEICONIC:
445 m_iconized = TRUE;
446 break;
447 }
448
449 if (!m_iconized)
450 {
451 // forward WM_SIZE to status bar control
452 #if USE_NATIVE_STATUSBAR
453 if (m_frameStatusBar && m_frameStatusBar->IsKindOf(CLASSINFO(wxStatusBar95)))
454 {
455 wxSizeEvent event(wxSize(x, y), m_frameStatusBar->GetId());
456 event.SetEventObject( m_frameStatusBar );
457
458 ((wxStatusBar95 *)m_frameStatusBar)->OnSize(event);
459 }
460 #endif
461
462 PositionStatusBar();
463
464 GetEventHandler()->OldOnSize(x, y);
465 }
466 }
467
468 bool wxMDIParentFrame::MSWOnActivate(const int state, const bool minimized, const WXHWND activate)
469 {
470 wxWindow::MSWOnActivate(state, minimized, activate);
471
472 // If this window is an MDI parent, we must also send an OnActivate message
473 // to the current child.
474 if ((m_currentChild != NULL) && ((state == WA_ACTIVE) || (state == WA_CLICKACTIVE)))
475 {
476 #if WXWIN_COMPATIBILITY
477 m_currentChild->GetEventHandler()->OldOnActivate(TRUE);
478 #else
479 wxActivateEvent event(wxEVT_ACTIVATE, TRUE,
480 m_currentChild.m_windowId);
481 event.eventObject = m_currentChild;
482 m_currentChild->GetEventHandler()->ProcessEvent(event);
483 #endif
484 }
485 return 0;
486 }
487
488 bool wxMDIParentFrame::MSWOnCommand(const WXWORD id, const WXWORD cmd, const WXHWND control)
489 {
490 if (cmd == 0)
491 {
492 // In case it's e.g. a toolbar.
493 wxWindow *win = wxFindWinFromHandle(control);
494 if (win)
495 return win->MSWCommand(cmd, id);
496
497 switch (id)
498 {
499 case IDM_WINDOWCASCADE:
500 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDICASCADE, MDITILE_SKIPDISABLED, 0);
501 return TRUE;
502 case IDM_WINDOWTILE:
503 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDITILE, MDITILE_HORIZONTAL, 0);
504 return TRUE;
505 case IDM_WINDOWICONS:
506 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIICONARRANGE, 0, 0);
507 return TRUE;
508 case IDM_WINDOWNEXT:
509 SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 0);
510 return TRUE;
511 default:
512 break;
513 }
514 if (id >= 0xF000)
515 {
516 #if DEBUG > 1
517 wxDebugMsg("wxMDIFrame::OnCommand %d: system command: calling default window proc\n", GetHWND());
518 #endif
519 return FALSE; // Get WndProc to call default proc
520 }
521
522 if (m_parentFrameActive && (id < wxFIRST_MDI_CHILD || id > wxLAST_MDI_CHILD))
523 {
524 ProcessCommand(id);
525 return TRUE;
526 }
527 else if (m_currentChild && (id < wxFIRST_MDI_CHILD || id > wxLAST_MDI_CHILD))
528 {
529 #if DEBUG > 1
530 wxDebugMsg("wxMDIFrame::MSWOnCommand %d: calling child OnCommand\n", GetHWND());
531 #endif
532 return m_currentChild->MSWOnCommand(id, cmd, control);
533 }
534 }
535 if (id >= wxFIRST_MDI_CHILD && id <= wxLAST_MDI_CHILD)
536 {
537 wxNode* node = GetChildren()->First();
538 while (node)
539 {
540 wxWindow* child = (wxWindow*) node->Data();
541 if (child->GetHWND())
542 {
543 #ifdef __WIN32__
544 long childId = GetWindowLong((HWND) child->GetHWND(), GWL_ID);
545 #else
546 long childId = GetWindowWord((HWND) child->GetHWND(), GWW_ID);
547 #endif
548 if (childId == id)
549 {
550 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDIACTIVATE, (WPARAM) (HWND) child->GetHWND(), 0);
551 return TRUE;
552 }
553 }
554 node = node->Next();
555 }
556 /*
557 wxWindow* child = FindItem(id);
558 if (child)
559 {
560 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDIACTIVATE, (WPARAM) (HWND) child->GetHWND(), 0);
561 return TRUE;
562 }
563 */
564 }
565
566 return FALSE;
567 }
568
569 void wxMDIParentFrame::MSWOnMenuHighlight(const WXWORD nItem, const WXWORD nFlags, const WXHMENU hSysMenu)
570 {
571 if (m_parentFrameActive)
572 {
573 // TODO
574 if (nFlags == 0xFFFF && hSysMenu == (WXHMENU) NULL)
575 GetEventHandler()->OldOnMenuSelect(-1);
576 else if (nFlags != MF_SEPARATOR)
577 GetEventHandler()->OldOnMenuSelect(nItem);
578 }
579 else if (m_currentChild)
580 {
581 m_currentChild->MSWOnMenuHighlight(nItem, nFlags, hSysMenu);
582 }
583 }
584
585 long wxMDIParentFrame::MSWDefWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
586 {
587 WXHWND clientWnd;
588 if ( GetClientWindow() )
589 clientWnd = GetClientWindow()->GetHWND();
590 else
591 clientWnd = 0;
592
593 return DefFrameProc((HWND) GetHWND(), (HWND) clientWnd, message, wParam, lParam);
594 }
595
596 bool wxMDIParentFrame::MSWProcessMessage(WXMSG* msg)
597 {
598 MSG *pMsg = (MSG *)msg;
599
600 if ((m_currentChild != (wxWindow *)NULL) && (m_currentChild->GetHWND() != (WXHWND) NULL) && m_currentChild->MSWProcessMessage(msg))
601 return TRUE;
602
603 if (m_acceleratorTable != (WXHANDLE) NULL &&
604 ::TranslateAccelerator((HWND) GetHWND(), (HANDLE) m_acceleratorTable, pMsg))
605 return TRUE;
606
607 if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN)
608 {
609 if (::TranslateMDISysAccel((HWND) GetClientWindow()->GetHWND(), pMsg))
610 return TRUE;
611 }
612
613 return FALSE;
614 }
615
616 bool wxMDIParentFrame::MSWOnEraseBkgnd(const WXHDC WXUNUSED(pDC))
617 {
618 return TRUE;
619 }
620
621 extern wxWindow *wxWndHook;
622 extern wxList *wxWinHandleList;
623
624 wxMDIChildFrame::wxMDIChildFrame(void)
625 {
626 // m_active = FALSE;
627 }
628
629 bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
630 const wxWindowID id,
631 const wxString& title,
632 const wxPoint& pos,
633 const wxSize& size,
634 const long style,
635 const wxString& name)
636 {
637 m_defaultIcon = (WXHICON) (wxSTD_MDICHILDFRAME_ICON ? wxSTD_MDICHILDFRAME_ICON : wxDEFAULT_MDICHILDFRAME_ICON);
638
639 SetName(name);
640
641 if ( id > -1 )
642 m_windowId = id;
643 else
644 m_windowId = (int)NewControlId();
645
646 if (parent) parent->AddChild(this);
647
648 wxWndHook = this;
649
650 int x = pos.x;
651 int y = pos.y;
652 int width = size.x;
653 int height = size.y;
654
655 MDICREATESTRUCT mcs;
656
657 mcs.szClass = wxMDIChildFrameClassName;
658 mcs.szTitle = title;
659 mcs.hOwner = wxGetInstance();
660 if (x > -1) mcs.x = x;
661 else mcs.x = CW_USEDEFAULT;
662
663 if (y > -1) mcs.y = y;
664 else mcs.y = CW_USEDEFAULT;
665
666 if (width > -1) mcs.cx = width;
667 else mcs.cx = CW_USEDEFAULT;
668
669 if (height > -1) mcs.cy = height;
670 else mcs.cy = CW_USEDEFAULT;
671
672 DWORD msflags = WS_OVERLAPPED | WS_CLIPCHILDREN ;
673 if (style & wxMINIMIZE_BOX)
674 msflags |= WS_MINIMIZEBOX;
675 if (style & wxMAXIMIZE_BOX)
676 msflags |= WS_MAXIMIZEBOX;
677 if (style & wxTHICK_FRAME)
678 msflags |= WS_THICKFRAME;
679 if (style & wxSYSTEM_MENU)
680 msflags |= WS_SYSMENU;
681 if ((style & wxMINIMIZE) || (style & wxICONIZE))
682 msflags |= WS_MINIMIZE;
683 if (style & wxMAXIMIZE)
684 msflags |= WS_MAXIMIZE;
685 if (style & wxCAPTION)
686 msflags |= WS_CAPTION;
687
688 mcs.style = msflags;
689
690 mcs.lParam = 0;
691
692 DWORD Return = SendMessage((HWND) parent->GetClientWindow()->GetHWND(),
693 WM_MDICREATE, 0, (LONG)(LPSTR)&mcs);
694
695 //handle = (HWND)LOWORD(Return);
696 // Must be the DWORRD for WIN32. And in 16 bits, HIWORD=0 (says Microsoft)
697 m_hWnd = (WXHWND)Return;
698
699 // This gets reassigned so can't be stored
700 // m_windowId = GetWindowLong((HWND) m_hWnd, GWL_ID);
701
702 wxWndHook = NULL;
703 wxWinHandleList->Append((long)GetHWND(), this);
704
705 SetWindowLong((HWND) GetHWND(), 0, (long)this);
706
707 wxModelessWindows.Append(this);
708 return TRUE;
709 }
710
711 wxMDIChildFrame::~wxMDIChildFrame(void)
712 {
713 MSWDestroyWindow();
714
715 ResetWindowStyle(NULL);
716 }
717
718 // Set the client size (i.e. leave the calculation of borders etc.
719 // to wxWindows)
720 void wxMDIChildFrame::SetClientSize(const int width, const int height)
721 {
722 HWND hWnd = (HWND) GetHWND();
723
724 RECT rect;
725 GetClientRect(hWnd, &rect);
726
727 RECT rect2;
728 GetWindowRect(hWnd, &rect2);
729
730 // Find the difference between the entire window (title bar and all)
731 // and the client area; add this to the new client size to move the
732 // window
733 int actual_width = rect2.right - rect2.left - rect.right + width;
734 int actual_height = rect2.bottom - rect2.top - rect.bottom + height;
735
736 if (GetStatusBar())
737 {
738 int sx, sy;
739 GetStatusBar()->GetSize(&sx, &sy);
740 actual_height += sy;
741 }
742
743 POINT point;
744 point.x = rect2.left;
745 point.y = rect2.top;
746
747 // If there's an MDI parent, must subtract the parent's top left corner
748 // since MoveWindow moves relative to the parent
749 wxMDIParentFrame *mdiParent = (wxMDIParentFrame *)GetParent();
750 ::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
751
752 MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)TRUE);
753 #if WXWIN_COMPATIBILITY
754 GetEventHandler()->OldOnSize(width, height);
755 #else
756 wxSizeEvent event(wxSize(width, height), m_windowId);
757 event.eventObject = this;
758 GetEventHandler()->ProcessEvent(event);
759 #endif
760 }
761
762 void wxMDIChildFrame::GetPosition(int *x, int *y) const
763 {
764 RECT rect;
765 GetWindowRect((HWND) GetHWND(), &rect);
766 POINT point;
767 point.x = rect.left;
768 point.y = rect.top;
769
770 // Since we now have the absolute screen coords,
771 // if there's a parent we must subtract its top left corner
772 wxMDIParentFrame *mdiParent = (wxMDIParentFrame *)GetParent();
773 ::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
774
775 *x = point.x;
776 *y = point.y;
777 }
778
779 void wxMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar)
780 {
781 if (!menu_bar)
782 {
783 m_frameMenuBar = NULL;
784 return;
785 }
786
787 if (menu_bar->m_menuBarFrame)
788 return;
789
790 int i;
791 HMENU menu = CreateMenu();
792
793 for (i = 0; i < menu_bar->m_menuCount; i ++)
794 {
795 HMENU popup = (HMENU)menu_bar->m_menus[i]->m_hMenu;
796 //
797 // After looking Bounds Checker result, it seems that all
798 // menus must be individually destroyed. So, don't reset m_hMenu,
799 // to allow ~wxMenu to do the job.
800 //
801 menu_bar->m_menus[i]->m_savehMenu = (WXHMENU) popup;
802 // Uncommenting for the moment... JACS
803 menu_bar->m_menus[i]->m_hMenu = 0;
804 ::AppendMenu((HMENU) menu, MF_POPUP | MF_STRING, (UINT)popup, menu_bar->m_titles[i]);
805 }
806
807 menu_bar->m_hMenu = (WXHMENU)menu;
808 if (m_frameMenuBar)
809 delete m_frameMenuBar;
810
811 this->m_hMenu = (WXHMENU) menu;
812
813 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
814
815 parent->m_parentFrameActive = FALSE;
816 HMENU subMenu = GetSubMenu((HWND) parent->GetWindowMenu(), 0);
817
818 // Try to insert Window menu in front of Help, otherwise append it.
819 int N = GetMenuItemCount(menu);
820 bool success = FALSE;
821 for (i = 0; i < N; i++)
822 {
823 char buf[100];
824 int chars = GetMenuString(menu, i, buf, 100, MF_BYPOSITION);
825 if ((chars > 0) && (strcmp(buf, "&Help") == 0 ||
826 strcmp(buf, "Help") == 0))
827 {
828 success = TRUE;
829 InsertMenu(menu, i, MF_BYPOSITION | MF_POPUP | MF_STRING,
830 (UINT)subMenu, "&Window");
831 break;
832 }
833 }
834 if (!success)
835 AppendMenu(menu, MF_POPUP,
836 (UINT)subMenu,
837 "&Window");
838 #ifdef __WIN32__
839 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU,
840 (WPARAM)menu,
841 (LPARAM)subMenu);
842 #else
843 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
844 MAKELPARAM(menu, subMenu));
845 #endif
846
847 DrawMenuBar((HWND) parent->GetHWND());
848 m_frameMenuBar = menu_bar;
849 menu_bar->m_menuBarFrame = this;
850 }
851
852 // MDI operations
853 void wxMDIChildFrame::Maximize(void)
854 {
855 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
856 if ( parent && parent->GetClientWindow() )
857 ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIMAXIMIZE, (WPARAM) (HWND) GetHWND(), 0);
858 }
859
860 void wxMDIChildFrame::Restore(void)
861 {
862 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
863 if ( parent && parent->GetClientWindow() )
864 ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIRESTORE, (WPARAM) (HWND) GetHWND(), 0);
865 }
866
867 void wxMDIChildFrame::Activate(void)
868 {
869 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
870 if ( parent && parent->GetClientWindow() )
871 ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIACTIVATE, (WPARAM) (HWND) GetHWND(), 0);
872 }
873
874 static HWND invalidHandle = 0;
875 void wxMDIChildFrame::MSWOnSize(const int x, const int y, const WXUINT id)
876 {
877 if (!GetHWND()) return;
878
879 if (invalidHandle == (HWND) GetHWND())
880 {
881 #if DEBUG > 1
882 wxDebugMsg("wxMDIChildFrame::OnSize %d: invalid, so returning.\n", GetHWND());
883 #endif
884 return;
885 }
886
887 (void)MSWDefWindowProc(m_lastMsg, m_lastWParam, m_lastLParam);
888
889 switch (id)
890 {
891 case SIZEFULLSCREEN:
892 case SIZENORMAL:
893 m_iconized = FALSE;
894 break;
895 case SIZEICONIC:
896 m_iconized = TRUE;
897 break;
898 }
899
900 if (!m_iconized)
901 {
902 // forward WM_SIZE to status bar control
903 #if USE_NATIVE_STATUSBAR
904 if (m_frameStatusBar && m_frameStatusBar->IsKindOf(CLASSINFO(wxStatusBar95)))
905 {
906 wxSizeEvent event(wxSize(x, y), m_frameStatusBar->GetId());
907 event.SetEventObject( m_frameStatusBar );
908
909 ((wxStatusBar95 *)m_frameStatusBar)->OnSize(event);
910 }
911 #endif
912
913 PositionStatusBar();
914
915 wxWindow::MSWOnSize(x, y, id);
916 }
917 }
918
919 bool wxMDIChildFrame::MSWOnCommand(const WXWORD id, const WXWORD cmd, const WXHWND control)
920 {
921 #if DEBUG > 1
922 wxDebugMsg("wxMDIChildFrame::MSWOnCommand %d\n", GetHWND());
923 #endif
924 if ((cmd == 0) && GetHWND())
925 {
926 // In case it's e.g. a toolbar.
927 wxWindow *win = wxFindWinFromHandle(control);
928 if (win)
929 return win->MSWCommand(cmd, id);
930
931 if (GetMenuBar() && GetMenuBar()->FindItemForId(id))
932 {
933 ProcessCommand(id);
934 return TRUE;
935 }
936 else
937 return FALSE;
938 return TRUE;
939 }
940 else
941 return FALSE;
942 }
943
944 long wxMDIChildFrame::MSWDefWindowProc(WXUINT message, WXUINT wParam, WXLPARAM lParam)
945 {
946 if (GetHWND())
947 return DefMDIChildProc((HWND) GetHWND(), (UINT) message, (WPARAM) wParam, (LPARAM) lParam);
948 else return 0;
949 }
950
951 bool wxMDIChildFrame::MSWProcessMessage(WXMSG *msg)
952 {
953 MSG *pMsg = (MSG *)msg;
954 if (m_acceleratorTable && GetHWND())
955 {
956 wxFrame *parent = (wxFrame *)GetParent();
957 HWND parent_hwnd = (HWND) parent->GetHWND();
958 return (::TranslateAccelerator(parent_hwnd, (HANDLE) m_acceleratorTable, pMsg) != 0);
959 }
960 return FALSE;
961 }
962
963 long wxMDIChildFrame::MSWOnMDIActivate(const long activate, const WXHWND WXUNUSED(one), const WXHWND WXUNUSED(two))
964 {
965 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
966 HMENU parent_menu = (HMENU) parent->GetWinMenu();
967 #if DEBUG > 1
968 wxDebugMsg("Parent menu is %d\n", parent_menu);
969 #endif
970 HMENU child_menu = (HMENU) GetWinMenu();
971 #if DEBUG > 1
972 wxDebugMsg("Child menu is %d\n", child_menu);
973 #endif
974
975 if (activate)
976 {
977 // m_active = TRUE;
978 parent->m_currentChild = this;
979 if (child_menu)
980 {
981 parent->m_parentFrameActive = FALSE;
982 HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0);
983 #if DEBUG > 1
984 wxDebugMsg("Window submenu is %d\n", subMenu);
985 #endif
986 // HMENU subMenu = 0;
987 #ifdef __WIN32__
988 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU,
989 (WPARAM)child_menu,
990 (LPARAM)subMenu);
991 #else
992 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
993 MAKELONG(child_menu, subMenu));
994 #endif
995
996 ::DrawMenuBar((HWND) parent->GetHWND());
997 }
998 GetEventHandler()->OldOnActivate(TRUE);
999 }
1000 else
1001 {
1002 if (parent->m_currentChild == this)
1003 parent->m_currentChild = NULL;
1004 GetEventHandler()->OldOnActivate(FALSE);
1005
1006 // m_active = FALSE;
1007 if (parent_menu)
1008 {
1009 parent->m_parentFrameActive = TRUE;
1010 HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0);
1011 #if DEBUG > 1
1012 wxDebugMsg("Window submenu is %d\n", subMenu);
1013 #endif
1014 // HMENU subMenu = 0;
1015 #ifdef __WIN32__
1016 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU,
1017 (WPARAM)parent_menu,
1018 (LPARAM)subMenu);
1019 #else
1020 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
1021 MAKELONG(parent_menu, subMenu));
1022 #endif
1023
1024 ::DrawMenuBar((HWND) parent->GetHWND());
1025 }
1026 }
1027 // TODO
1028 bool flag = (activate != 0);
1029 GetEventHandler()->OldOnActivate(flag);
1030 #if DEBUG > 1
1031 wxDebugMsg("Finished (de)activating\n");
1032 #endif
1033 return 0;
1034 }
1035
1036 void wxMDIChildFrame::MSWDestroyWindow(void)
1037 {
1038 MSWDetachWindowMenu();
1039 invalidHandle = (HWND) GetHWND();
1040
1041 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
1042
1043 // Must make sure this handle is invalidated (set to NULL)
1044 // since all sorts of things could happen after the
1045 // child client is destroyed, but before the wxFrame is
1046 // destroyed.
1047
1048 HWND oldHandle = (HWND)GetHWND();
1049 #if DEBUG > 1
1050 wxDebugMsg("*** About to DestroyWindow MDI child %d\n", oldHandle);
1051 #endif
1052 #ifdef __WIN32__
1053 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDIDESTROY, (WPARAM)oldHandle, (LPARAM)0);
1054 #else
1055 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDIDESTROY, (HWND)oldHandle, 0);
1056 #endif
1057 #if DEBUG > 1
1058 wxDebugMsg("*** Finished DestroyWindow MDI child %d\n", oldHandle);
1059 #endif
1060 invalidHandle = 0;
1061
1062 if (m_hMenu)
1063 {
1064 ::DestroyMenu((HMENU) m_hMenu);
1065 m_hMenu = 0;
1066 }
1067 m_hWnd = 0;
1068 }
1069
1070 // Change the client window's extended style so we don't
1071 // get a client edge style when a child is maximised (a double
1072 // border looks silly.)
1073 bool wxMDIChildFrame::ResetWindowStyle(void *vrect)
1074 {
1075 #if defined(__WIN95__)
1076 RECT *rect = (RECT *)vrect;
1077 wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent();
1078 wxMDIChildFrame* pChild = pFrameWnd->GetActiveChild();
1079 if (!pChild || (pChild == this))
1080 {
1081 DWORD dwStyle = ::GetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE);
1082 DWORD dwThisStyle = ::GetWindowLong((HWND) GetHWND(), GWL_STYLE);
1083 DWORD dwNewStyle = dwStyle;
1084 if (pChild != NULL && (dwThisStyle & WS_MAXIMIZE))
1085 dwNewStyle &= ~(WS_EX_CLIENTEDGE);
1086 else
1087 dwNewStyle |= WS_EX_CLIENTEDGE;
1088
1089 if (dwStyle != dwNewStyle)
1090 {
1091 ::RedrawWindow((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
1092 ::SetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE, dwNewStyle);
1093 ::SetWindowPos((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, 0, 0, 0, 0,
1094 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOCOPYBITS);
1095 if (rect)
1096 ::GetClientRect((HWND) pFrameWnd->GetClientWindow()->GetHWND(), rect);
1097 return TRUE;
1098 }
1099 }
1100 return FALSE;
1101 #else
1102 return FALSE;
1103 #endif
1104 }
1105
1106 void wxMDIChildFrame::MSWOnWindowPosChanging(void *pos)
1107 {
1108 WINDOWPOS *lpPos = (WINDOWPOS *)pos;
1109 #if defined(__WIN95__)
1110 if (!(lpPos->flags & SWP_NOSIZE))
1111 {
1112 RECT rectClient;
1113 DWORD dwExStyle = ::GetWindowLong((HWND) GetHWND(), GWL_EXSTYLE);
1114 DWORD dwStyle = ::GetWindowLong((HWND) GetHWND(), GWL_STYLE);
1115 if (ResetWindowStyle((void *) & rectClient) && (dwStyle & WS_MAXIMIZE))
1116 {
1117 ::AdjustWindowRectEx(&rectClient, dwStyle, FALSE, dwExStyle);
1118 lpPos->x = rectClient.left;
1119 lpPos->y = rectClient.top;
1120 lpPos->cx = rectClient.right - rectClient.left;
1121 lpPos->cy = rectClient.bottom - rectClient.top;
1122 }
1123 wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent();
1124 if (pFrameWnd && pFrameWnd->GetToolBar())
1125 {
1126 pFrameWnd->GetToolBar()->Refresh();
1127 }
1128 }
1129 #endif
1130 Default();
1131 }
1132
1133 // Client window
1134 wxMDIClientWindow::wxMDIClientWindow(void)
1135 {
1136 m_scrollX = 0;
1137 m_scrollY = 0;
1138 }
1139
1140 wxMDIClientWindow::~wxMDIClientWindow(void)
1141 {
1142 }
1143
1144 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, const long style)
1145 {
1146 m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE);
1147
1148 CLIENTCREATESTRUCT ccs;
1149 m_windowStyle = style;
1150 m_windowParent = parent;
1151
1152 ccs.hWindowMenu = (HMENU) parent->GetWindowMenu();
1153 ccs.idFirstChild = wxFIRST_MDI_CHILD;
1154
1155 DWORD msStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN ;
1156 if ( parent->GetWindowStyleFlag() & wxHSCROLL )
1157 msStyle |= WS_HSCROLL;
1158 if ( parent->GetWindowStyleFlag() & wxVSCROLL )
1159 msStyle |= WS_VSCROLL ;
1160
1161 #if defined(__WIN95__)
1162 DWORD exStyle = WS_EX_CLIENTEDGE;
1163 #else
1164 DWORD exStyle = 0;
1165 #endif
1166
1167 wxWndHook = this;
1168 m_hWnd = (WXHWND) ::CreateWindowEx(exStyle, "mdiclient", NULL,
1169 msStyle, 0, 0, 0, 0, (HWND) parent->GetHWND(), NULL,
1170 wxGetInstance(), (LPSTR)(LPCLIENTCREATESTRUCT)&ccs);
1171 SubclassWin(m_hWnd);
1172 wxWndHook = NULL;
1173
1174 return (m_hWnd != 0) ;
1175 }
1176
1177 // Window procedure: here for debugging purposes
1178 long wxMDIClientWindow::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
1179 {
1180 return wxWindow::MSWWindowProc(nMsg, wParam, lParam);
1181 // return MSWDefWindowProc(nMsg, wParam, lParam);
1182 }
1183
1184 long wxMDIClientWindow::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
1185 {
1186 if ( MSWGetOldWndProc() != 0)
1187 return ::CallWindowProc(CASTWNDPROC (FARPROC) MSWGetOldWndProc(), (HWND) GetHWND(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
1188 else
1189 return ::DefWindowProc((HWND) m_hWnd, (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
1190 }
1191
1192 // Explicitly call default scroll behaviour
1193 void wxMDIClientWindow::OnScroll(wxScrollEvent& event)
1194 {
1195 // Note: for client windows, the scroll position is not set in
1196 // WM_HSCROLL, WM_VSCROLL, so we can't easily determine what
1197 // scroll position we're at.
1198 // This makes it hard to paint patterns or bitmaps in the background,
1199 // and have the client area scrollable as well.
1200
1201 if ( event.GetOrientation() == wxHORIZONTAL )
1202 m_scrollX = event.GetPosition(); // Always returns zero!
1203 else
1204 m_scrollY = event.GetPosition(); // Always returns zero!
1205
1206 Default();
1207 }
1208
1209 // Should hand the message to the default proc
1210 long wxMDIClientWindow::MSWOnMDIActivate(const long bActivate, const WXHWND, const WXHWND)
1211 {
1212 return Default();
1213 }
1214