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