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