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