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