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