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