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