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