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