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