]> git.saurik.com Git - wxWidgets.git/blame - src/msw/mdi.cpp
* Fixed Async -> sync in wxExecute
[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
37#if USE_NATIVE_STATUSBAR
38#include <wx/msw/statbr95.h>
39#endif
40
41#include <string.h>
42
43extern 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
58extern char wxMDIFrameClassName[];
59extern char wxMDIChildFrameClassName[];
60extern wxWindow *wxWndHook;
61
62#if !USE_SHARED_LIBRARY
63IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame)
64IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame)
65IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxWindow)
66
67BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
68 EVT_SIZE(wxMDIParentFrame::OnSize)
69 EVT_ACTIVATE(wxMDIParentFrame::OnActivate)
70 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged)
71END_EVENT_TABLE()
72
73BEGIN_EVENT_TABLE(wxMDIClientWindow, wxWindow)
74 EVT_SCROLL(wxMDIClientWindow::OnScroll)
75END_EVENT_TABLE()
76
77#endif
78
79wxMDIParentFrame::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
88bool wxMDIParentFrame::Create(wxWindow *parent,
89 const wxWindowID id,
90 const wxString& title,
91 const wxPoint& pos,
92 const wxSize& size,
93 const long style,
94 const wxString& name)
95{
96 m_defaultIcon = (WXHICON) (wxSTD_MDIPARENTFRAME_ICON ? wxSTD_MDIPARENTFRAME_ICON : wxDEFAULT_MDIPARENTFRAME_ICON);
97
98 m_frameToolBar = NULL ;
99 m_clientWindow = NULL;
100 m_currentChild = NULL;
101 m_windowMenu = 0;
102 m_parentFrameActive = TRUE;
103
104 if (!parent)
105 wxTopLevelWindows.Append(this);
106
107 SetName(name);
108 m_windowStyle = style;
109
110 if (parent) parent->AddChild(this);
111
112 if ( id > -1 )
113 m_windowId = id;
114 else
115 m_windowId = (int)NewControlId();
116
117 int x = pos.x;
118 int y = pos.y;
119 int width = size.x;
120 int height = size.y;
121
122 m_windowMenu = (WXHMENU) ::LoadMenu(wxGetInstance(), "wxWindowMenu");
123
124#if DEBUG > 1
125 wxDebugMsg("Loaded m_windowMenu %d\n", m_windowMenu);
126#endif
127
46851318 128 DWORD msflags = WS_OVERLAPPED ;
2bda0e17
KB
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;
46851318
JS
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;
2bda0e17
KB
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
157wxMDIParentFrame::~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.
172void 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
198void 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
271void 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
300void wxMDIParentFrame::OnActivate(wxActivateEvent& event)
301{
302 // Do nothing
303}
304
305#if WXWIN_COMPATIBILITY
306void wxMDIParentFrame::OldOnSize(int x, int y)
307{
308#if WXWIN_COMPATIBILITY == 1
309 wxSizeEvent event(wxSize(x, y), m_windowId);
310 event.SetEventObject( this );
311 GetEventHandler()->ProcessEvent(event);
312#else
313
314#if USE_CONSTRAINTS
315 if (GetAutoLayout())
316 Layout();
317#endif
318 int x = 0;
319 int y = 0;
320 int width, height;
321 GetClientSize(&width, &height);
322 if ( GetToolBar() )
323 {
324 int wt, ht;
325 GetToolBar()->GetSize(&wt, &ht);
326 height -= ht;
327 y += ht;
328 }
329
330 if ( GetClientWindow() )
331 GetClientWindow()->SetSize(x, y, width, height);
332
333#endif
334}
335
336// Default activation behaviour - nothing.
337// Default activation behaviour - override dedault wxFrame behaviour
338void wxMDIParentFrame::OldOnActivate(bool flag)
339{
340#if WXWIN_COMPATIBILITY == 1
341 wxActivateEvent event(wxEVT_ACTIVATE, flag, m_windowId);
342 event.SetEventObject( this );
343 GetEventHandler()->ProcessEvent(event);
344#else
345#endif
346}
347
348#endif
349
350// Returns the active MDI child window
351wxMDIChildFrame *wxMDIParentFrame::GetActiveChild(void) const
352{
353// HWND hWnd = (HWND)LOWORD(SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIGETACTIVE, 0, 0L));
354 HWND hWnd = (HWND)SendMessage((HWND) GetClientWindow()->GetHWND(), WM_MDIGETACTIVE, 0, 0L);
355 if (hWnd == 0)
356 return NULL;
357 else
358 return (wxMDIChildFrame *)wxFindWinFromHandle((WXHWND) hWnd);
359}
360
361// Create the client window class (don't Create the window,
362// just return a new class)
363wxMDIClientWindow *wxMDIParentFrame::OnCreateClient(void)
364{
365 return new wxMDIClientWindow ;
366}
367
368// Responds to colour changes, and passes event on to children.
369void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
370{
371 if ( m_clientWindow )
372 {
373 m_clientWindow->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE));
374 m_clientWindow->Refresh();
375 }
376/*
377 if ( m_frameToolBar )
378 {
379 wxSysColourChangedEvent event2;
380 event2.eventObject = m_frameToolBar;
381 m_frameToolBar->GetEventHandler()->ProcessEvent(event2);
382 }
383*/
384
385 // Propagate the event to the non-top-level children
386 wxFrame::OnSysColourChanged(event);
387}
388
389// MDI operations
390void wxMDIParentFrame::Cascade(void)
391{
392 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDICASCADE, 0, 0);
393}
394
395void wxMDIParentFrame::Tile(void)
396{
397 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDITILE, MDITILE_HORIZONTAL, 0);
398}
399
400void wxMDIParentFrame::ArrangeIcons(void)
401{
402 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDIICONARRANGE, 0, 0);
403}
404
405void wxMDIParentFrame::ActivateNext(void)
406{
407 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 0);
408}
409
410void wxMDIParentFrame::ActivatePrevious(void)
411{
412 ::SendMessage( (HWND) GetClientWindow()->GetHWND(), WM_MDINEXT, 0, 1);
413}
414
415
416/*
417// Returns a style for the client window - usually 0
418// or, for example, wxHSCROLL | wxVSCROLL
419long wxMDIParentFrame::GetClientStyle(void) const
420{
421 return wxHSCROLL | wxVSCROLL ;
422}
423*/
424
425bool wxMDIParentFrame::MSWOnDestroy(void)
426{
427 return FALSE;
428}
429
430void wxMDIParentFrame::MSWOnCreate(WXLPCREATESTRUCT WXUNUSED(cs))
431{
432 m_clientWindow = new wxMDIClientWindow;
433 // Uses own style for client style
434 m_clientWindow->CreateClient(this, GetWindowStyleFlag());
435}
436
437void wxMDIParentFrame::MSWOnSize(const int x, const int y, const WXUINT id)
438{
439 switch (id)
440 {
441 case SIZEFULLSCREEN:
442 case SIZENORMAL:
443 m_iconized = FALSE;
444 break;
445 case SIZEICONIC:
446 m_iconized = TRUE;
447 break;
448 }
449
450 if (!m_iconized)
451 {
452 // forward WM_SIZE to status bar control
453#if USE_NATIVE_STATUSBAR
454 if (m_frameStatusBar && m_frameStatusBar->IsKindOf(CLASSINFO(wxStatusBar95)))
455 {
456 wxSizeEvent event(wxSize(x, y), m_frameStatusBar->GetId());
457 event.SetEventObject( m_frameStatusBar );
458
459 ((wxStatusBar95 *)m_frameStatusBar)->OnSize(event);
460 }
461#endif
462
463 PositionStatusBar();
464
465 GetEventHandler()->OldOnSize(x, y);
466 }
467}
468
469bool wxMDIParentFrame::MSWOnActivate(const int state, const bool minimized, const WXHWND activate)
470{
471 wxWindow::MSWOnActivate(state, minimized, activate);
472
473 // If this window is an MDI parent, we must also send an OnActivate message
474 // to the current child.
475 if ((m_currentChild != NULL) && ((state == WA_ACTIVE) || (state == WA_CLICKACTIVE)))
476 {
477#if WXWIN_COMPATIBILITY
478 m_currentChild->GetEventHandler()->OldOnActivate(TRUE);
479#else
480 wxActivateEvent event(wxEVT_ACTIVATE, TRUE,
481 m_currentChild.m_windowId);
482 event.eventObject = m_currentChild;
483 m_currentChild->GetEventHandler()->ProcessEvent(event);
484#endif
485 }
486 return 0;
487}
488
489bool wxMDIParentFrame::MSWOnCommand(const WXWORD id, const WXWORD cmd, const 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 DEBUG > 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 DEBUG > 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
570void wxMDIParentFrame::MSWOnMenuHighlight(const WXWORD nItem, const WXWORD nFlags, const WXHMENU hSysMenu)
571{
572 if (m_parentFrameActive)
573 {
574 // TODO
575 if (nFlags == 0xFFFF && hSysMenu == (WXHMENU) NULL)
576 GetEventHandler()->OldOnMenuSelect(-1);
577 else if (nFlags != MF_SEPARATOR)
578 GetEventHandler()->OldOnMenuSelect(nItem);
579 }
580 else if (m_currentChild)
581 {
582 m_currentChild->MSWOnMenuHighlight(nItem, nFlags, hSysMenu);
583 }
584}
585
586long wxMDIParentFrame::MSWDefWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
587{
588 WXHWND clientWnd;
589 if ( GetClientWindow() )
590 clientWnd = GetClientWindow()->GetHWND();
591 else
592 clientWnd = 0;
593
594 return DefFrameProc((HWND) GetHWND(), (HWND) clientWnd, message, wParam, lParam);
595}
596
597bool wxMDIParentFrame::MSWProcessMessage(WXMSG* msg)
598{
599 MSG *pMsg = (MSG *)msg;
600
601 if ((m_currentChild != (wxWindow *)NULL) && (m_currentChild->GetHWND() != (WXHWND) NULL) && m_currentChild->MSWProcessMessage(msg))
602 return TRUE;
603
604 if (m_acceleratorTable != (WXHANDLE) NULL &&
605 ::TranslateAccelerator((HWND) GetHWND(), (HANDLE) m_acceleratorTable, pMsg))
606 return TRUE;
607
608 if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN)
609 {
610 if (::TranslateMDISysAccel((HWND) GetClientWindow()->GetHWND(), pMsg))
611 return TRUE;
612 }
613
614 return FALSE;
615}
616
617bool wxMDIParentFrame::MSWOnEraseBkgnd(const WXHDC WXUNUSED(pDC))
618{
619 return TRUE;
620}
621
622extern wxWindow *wxWndHook;
623extern wxList *wxWinHandleList;
624
625wxMDIChildFrame::wxMDIChildFrame(void)
626{
627// m_active = FALSE;
628}
629
630bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
631 const wxWindowID id,
632 const wxString& title,
633 const wxPoint& pos,
634 const wxSize& size,
635 const long style,
636 const wxString& name)
637{
638 m_defaultIcon = (WXHICON) (wxSTD_MDICHILDFRAME_ICON ? wxSTD_MDICHILDFRAME_ICON : wxDEFAULT_MDICHILDFRAME_ICON);
639
640 SetName(name);
641
642 if ( id > -1 )
643 m_windowId = id;
644 else
645 m_windowId = (int)NewControlId();
646
647 if (parent) parent->AddChild(this);
648
649 wxWndHook = this;
650
651 int x = pos.x;
652 int y = pos.y;
653 int width = size.x;
654 int height = size.y;
655
656 MDICREATESTRUCT mcs;
657
658 mcs.szClass = wxMDIChildFrameClassName;
659 mcs.szTitle = title;
660 mcs.hOwner = wxGetInstance();
661 if (x > -1) mcs.x = x;
662 else mcs.x = CW_USEDEFAULT;
663
664 if (y > -1) mcs.y = y;
665 else mcs.y = CW_USEDEFAULT;
666
667 if (width > -1) mcs.cx = width;
668 else mcs.cx = CW_USEDEFAULT;
669
670 if (height > -1) mcs.cy = height;
671 else mcs.cy = CW_USEDEFAULT;
672
673 DWORD msflags = WS_OVERLAPPED | WS_CLIPCHILDREN ;
674 if (style & wxMINIMIZE_BOX)
675 msflags |= WS_MINIMIZEBOX;
676 if (style & wxMAXIMIZE_BOX)
677 msflags |= WS_MAXIMIZEBOX;
678 if (style & wxTHICK_FRAME)
679 msflags |= WS_THICKFRAME;
680 if (style & wxSYSTEM_MENU)
681 msflags |= WS_SYSMENU;
682 if ((style & wxMINIMIZE) || (style & wxICONIZE))
683 msflags |= WS_MINIMIZE;
684 if (style & wxMAXIMIZE)
685 msflags |= WS_MAXIMIZE;
686 if (style & wxCAPTION)
687 msflags |= WS_CAPTION;
688
689 mcs.style = msflags;
690
691 mcs.lParam = 0;
692
693 DWORD Return = SendMessage((HWND) parent->GetClientWindow()->GetHWND(),
694 WM_MDICREATE, 0, (LONG)(LPSTR)&mcs);
695
696 //handle = (HWND)LOWORD(Return);
697 // Must be the DWORRD for WIN32. And in 16 bits, HIWORD=0 (says Microsoft)
698 m_hWnd = (WXHWND)Return;
699
700 // This gets reassigned so can't be stored
701// m_windowId = GetWindowLong((HWND) m_hWnd, GWL_ID);
702
703 wxWndHook = NULL;
704 wxWinHandleList->Append((long)GetHWND(), this);
705
706 SetWindowLong((HWND) GetHWND(), 0, (long)this);
707
708 wxModelessWindows.Append(this);
709 return TRUE;
710}
711
712wxMDIChildFrame::~wxMDIChildFrame(void)
713{
714 MSWDestroyWindow();
715
716 ResetWindowStyle(NULL);
717}
718
719// Set the client size (i.e. leave the calculation of borders etc.
720// to wxWindows)
721void wxMDIChildFrame::SetClientSize(const int width, const int height)
722{
723 HWND hWnd = (HWND) GetHWND();
724
725 RECT rect;
726 GetClientRect(hWnd, &rect);
727
728 RECT rect2;
729 GetWindowRect(hWnd, &rect2);
730
731 // Find the difference between the entire window (title bar and all)
732 // and the client area; add this to the new client size to move the
733 // window
734 int actual_width = rect2.right - rect2.left - rect.right + width;
735 int actual_height = rect2.bottom - rect2.top - rect.bottom + height;
736
737 if (GetStatusBar())
738 {
739 int sx, sy;
740 GetStatusBar()->GetSize(&sx, &sy);
741 actual_height += sy;
742 }
743
744 POINT point;
745 point.x = rect2.left;
746 point.y = rect2.top;
747
748 // If there's an MDI parent, must subtract the parent's top left corner
749 // since MoveWindow moves relative to the parent
750 wxMDIParentFrame *mdiParent = (wxMDIParentFrame *)GetParent();
751 ::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
752
753 MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)TRUE);
754#if WXWIN_COMPATIBILITY
755 GetEventHandler()->OldOnSize(width, height);
756#else
757 wxSizeEvent event(wxSize(width, height), m_windowId);
758 event.eventObject = this;
759 GetEventHandler()->ProcessEvent(event);
760#endif
761}
762
763void wxMDIChildFrame::GetPosition(int *x, int *y) const
764{
765 RECT rect;
766 GetWindowRect((HWND) GetHWND(), &rect);
767 POINT point;
768 point.x = rect.left;
769 point.y = rect.top;
770
771 // Since we now have the absolute screen coords,
772 // if there's a parent we must subtract its top left corner
773 wxMDIParentFrame *mdiParent = (wxMDIParentFrame *)GetParent();
774 ::ScreenToClient((HWND) mdiParent->GetClientWindow()->GetHWND(), &point);
775
776 *x = point.x;
777 *y = point.y;
778}
779
780void wxMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar)
781{
782 if (!menu_bar)
783 {
784 m_frameMenuBar = NULL;
785 return;
786 }
787
788 if (menu_bar->m_menuBarFrame)
789 return;
790
791 int i;
792 HMENU menu = CreateMenu();
793
794 for (i = 0; i < menu_bar->m_menuCount; i ++)
795 {
796 HMENU popup = (HMENU)menu_bar->m_menus[i]->m_hMenu;
797 //
798 // After looking Bounds Checker result, it seems that all
799 // menus must be individually destroyed. So, don't reset m_hMenu,
800 // to allow ~wxMenu to do the job.
801 //
802 menu_bar->m_menus[i]->m_savehMenu = (WXHMENU) popup;
803 // Uncommenting for the moment... JACS
804 menu_bar->m_menus[i]->m_hMenu = 0;
805 ::AppendMenu((HMENU) menu, MF_POPUP | MF_STRING, (UINT)popup, menu_bar->m_titles[i]);
806 }
807
808 menu_bar->m_hMenu = (WXHMENU)menu;
809 if (m_frameMenuBar)
810 delete m_frameMenuBar;
811
812 this->m_hMenu = (WXHMENU) menu;
813
814 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
815
816 parent->m_parentFrameActive = FALSE;
817 HMENU subMenu = GetSubMenu((HWND) parent->GetWindowMenu(), 0);
818
819 // Try to insert Window menu in front of Help, otherwise append it.
820 int N = GetMenuItemCount(menu);
821 bool success = FALSE;
822 for (i = 0; i < N; i++)
823 {
824 char buf[100];
825 int chars = GetMenuString(menu, i, buf, 100, MF_BYPOSITION);
826 if ((chars > 0) && (strcmp(buf, "&Help") == 0 ||
827 strcmp(buf, "Help") == 0))
828 {
829 success = TRUE;
830 InsertMenu(menu, i, MF_BYPOSITION | MF_POPUP | MF_STRING,
831 (UINT)subMenu, "&Window");
832 break;
833 }
834 }
835 if (!success)
836 AppendMenu(menu, MF_POPUP,
837 (UINT)subMenu,
838 "&Window");
839#ifdef __WIN32__
840 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU,
841 (WPARAM)menu,
842 (LPARAM)subMenu);
843#else
844 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
845 MAKELPARAM(menu, subMenu));
846#endif
847
848 DrawMenuBar((HWND) parent->GetHWND());
849 m_frameMenuBar = menu_bar;
850 menu_bar->m_menuBarFrame = this;
851}
852
853// MDI operations
854void wxMDIChildFrame::Maximize(void)
855{
856 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
857 if ( parent && parent->GetClientWindow() )
858 ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIMAXIMIZE, (WPARAM) (HWND) GetHWND(), 0);
859}
860
861void wxMDIChildFrame::Restore(void)
862{
863 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
864 if ( parent && parent->GetClientWindow() )
865 ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIRESTORE, (WPARAM) (HWND) GetHWND(), 0);
866}
867
868void wxMDIChildFrame::Activate(void)
869{
870 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
871 if ( parent && parent->GetClientWindow() )
872 ::SendMessage( (HWND) parent->GetClientWindow()->GetHWND(), WM_MDIACTIVATE, (WPARAM) (HWND) GetHWND(), 0);
873}
874
875static HWND invalidHandle = 0;
876void wxMDIChildFrame::MSWOnSize(const int x, const int y, const WXUINT id)
877{
878 if (!GetHWND()) return;
879
880 if (invalidHandle == (HWND) GetHWND())
881 {
882#if DEBUG > 1
883 wxDebugMsg("wxMDIChildFrame::OnSize %d: invalid, so returning.\n", GetHWND());
884#endif
885 return;
886 }
887
888 (void)MSWDefWindowProc(m_lastMsg, m_lastWParam, m_lastLParam);
889
890 switch (id)
891 {
892 case SIZEFULLSCREEN:
893 case SIZENORMAL:
894 m_iconized = FALSE;
895 break;
896 case SIZEICONIC:
897 m_iconized = TRUE;
898 break;
899 }
900
901 if (!m_iconized)
902 {
903 // forward WM_SIZE to status bar control
904#if USE_NATIVE_STATUSBAR
905 if (m_frameStatusBar && m_frameStatusBar->IsKindOf(CLASSINFO(wxStatusBar95)))
906 {
907 wxSizeEvent event(wxSize(x, y), m_frameStatusBar->GetId());
908 event.SetEventObject( m_frameStatusBar );
909
910 ((wxStatusBar95 *)m_frameStatusBar)->OnSize(event);
911 }
912#endif
913
914 PositionStatusBar();
915
916 wxWindow::MSWOnSize(x, y, id);
917 }
918}
919
920bool wxMDIChildFrame::MSWOnCommand(const WXWORD id, const WXWORD cmd, const WXHWND control)
921{
922#if DEBUG > 1
923 wxDebugMsg("wxMDIChildFrame::MSWOnCommand %d\n", GetHWND());
924#endif
925 if ((cmd == 0) && GetHWND())
926 {
927 // In case it's e.g. a toolbar.
928 wxWindow *win = wxFindWinFromHandle(control);
929 if (win)
930 return win->MSWCommand(cmd, id);
931
932 if (GetMenuBar() && GetMenuBar()->FindItemForId(id))
933 {
934 ProcessCommand(id);
935 return TRUE;
936 }
937 else
938 return FALSE;
939 return TRUE;
940 }
941 else
942 return FALSE;
943}
944
945long wxMDIChildFrame::MSWDefWindowProc(WXUINT message, WXUINT wParam, WXLPARAM lParam)
946{
947 if (GetHWND())
948 return DefMDIChildProc((HWND) GetHWND(), (UINT) message, (WPARAM) wParam, (LPARAM) lParam);
949 else return 0;
950}
951
952bool wxMDIChildFrame::MSWProcessMessage(WXMSG *msg)
953{
954 MSG *pMsg = (MSG *)msg;
955 if (m_acceleratorTable && GetHWND())
956 {
957 wxFrame *parent = (wxFrame *)GetParent();
958 HWND parent_hwnd = (HWND) parent->GetHWND();
959 return (::TranslateAccelerator(parent_hwnd, (HANDLE) m_acceleratorTable, pMsg) != 0);
960 }
961 return FALSE;
962}
963
964long wxMDIChildFrame::MSWOnMDIActivate(const long activate, const WXHWND WXUNUSED(one), const WXHWND WXUNUSED(two))
965{
966 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
967 HMENU parent_menu = (HMENU) parent->GetWinMenu();
968#if DEBUG > 1
969 wxDebugMsg("Parent menu is %d\n", parent_menu);
970#endif
971 HMENU child_menu = (HMENU) GetWinMenu();
972#if DEBUG > 1
973 wxDebugMsg("Child menu is %d\n", child_menu);
974#endif
975
976 if (activate)
977 {
978// m_active = TRUE;
979 parent->m_currentChild = this;
980 if (child_menu)
981 {
982 parent->m_parentFrameActive = FALSE;
983 HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0);
984#if DEBUG > 1
985 wxDebugMsg("Window submenu is %d\n", subMenu);
986#endif
987// HMENU subMenu = 0;
988#ifdef __WIN32__
989 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU,
990 (WPARAM)child_menu,
991 (LPARAM)subMenu);
992#else
993 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
994 MAKELONG(child_menu, subMenu));
995#endif
996
997 ::DrawMenuBar((HWND) parent->GetHWND());
998 }
999 GetEventHandler()->OldOnActivate(TRUE);
1000 }
1001 else
1002 {
1003 if (parent->m_currentChild == this)
1004 parent->m_currentChild = NULL;
1005 GetEventHandler()->OldOnActivate(FALSE);
1006
1007// m_active = FALSE;
1008 if (parent_menu)
1009 {
1010 parent->m_parentFrameActive = TRUE;
1011 HMENU subMenu = GetSubMenu((HMENU) parent->GetWindowMenu(), 0);
1012#if DEBUG > 1
1013 wxDebugMsg("Window submenu is %d\n", subMenu);
1014#endif
1015// HMENU subMenu = 0;
1016#ifdef __WIN32__
1017 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU,
1018 (WPARAM)parent_menu,
1019 (LPARAM)subMenu);
1020#else
1021 ::SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDISETMENU, 0,
1022 MAKELONG(parent_menu, subMenu));
1023#endif
1024
1025 ::DrawMenuBar((HWND) parent->GetHWND());
1026 }
1027 }
1028 // TODO
1029 bool flag = (activate != 0);
1030 GetEventHandler()->OldOnActivate(flag);
1031#if DEBUG > 1
1032 wxDebugMsg("Finished (de)activating\n");
1033#endif
1034 return 0;
1035}
1036
1037void wxMDIChildFrame::MSWDestroyWindow(void)
1038{
1039 MSWDetachWindowMenu();
1040 invalidHandle = (HWND) GetHWND();
1041
1042 wxMDIParentFrame *parent = (wxMDIParentFrame *)GetParent();
1043
1044 // Must make sure this handle is invalidated (set to NULL)
1045 // since all sorts of things could happen after the
1046 // child client is destroyed, but before the wxFrame is
1047 // destroyed.
1048
1049 HWND oldHandle = (HWND)GetHWND();
1050#if DEBUG > 1
1051 wxDebugMsg("*** About to DestroyWindow MDI child %d\n", oldHandle);
1052#endif
1053#ifdef __WIN32__
1054 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDIDESTROY, (WPARAM)oldHandle, (LPARAM)0);
1055#else
1056 SendMessage((HWND) parent->GetClientWindow()->GetHWND(), WM_MDIDESTROY, (HWND)oldHandle, 0);
1057#endif
1058#if DEBUG > 1
1059 wxDebugMsg("*** Finished DestroyWindow MDI child %d\n", oldHandle);
1060#endif
1061 invalidHandle = 0;
1062
1063 if (m_hMenu)
1064 {
1065 ::DestroyMenu((HMENU) m_hMenu);
1066 m_hMenu = 0;
1067 }
1068 m_hWnd = 0;
1069}
1070
1071// Change the client window's extended style so we don't
1072// get a client edge style when a child is maximised (a double
1073// border looks silly.)
1074bool wxMDIChildFrame::ResetWindowStyle(void *vrect)
1075{
1076#if defined(__WIN95__)
1077 RECT *rect = (RECT *)vrect;
1078 wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent();
1079 wxMDIChildFrame* pChild = pFrameWnd->GetActiveChild();
1080 if (!pChild || (pChild == this))
1081 {
1082 DWORD dwStyle = ::GetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE);
1083 DWORD dwThisStyle = ::GetWindowLong((HWND) GetHWND(), GWL_STYLE);
1084 DWORD dwNewStyle = dwStyle;
1085 if (pChild != NULL && (dwThisStyle & WS_MAXIMIZE))
1086 dwNewStyle &= ~(WS_EX_CLIENTEDGE);
1087 else
1088 dwNewStyle |= WS_EX_CLIENTEDGE;
1089
1090 if (dwStyle != dwNewStyle)
1091 {
1092 ::RedrawWindow((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
1093 ::SetWindowLong((HWND) pFrameWnd->GetClientWindow()->GetHWND(), GWL_EXSTYLE, dwNewStyle);
1094 ::SetWindowPos((HWND) pFrameWnd->GetClientWindow()->GetHWND(), NULL, 0, 0, 0, 0,
1095 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOCOPYBITS);
1096 if (rect)
1097 ::GetClientRect((HWND) pFrameWnd->GetClientWindow()->GetHWND(), rect);
1098 return TRUE;
1099 }
1100 }
1101 return FALSE;
1102#else
1103 return FALSE;
1104#endif
1105}
1106
1107void wxMDIChildFrame::MSWOnWindowPosChanging(void *pos)
1108{
1109 WINDOWPOS *lpPos = (WINDOWPOS *)pos;
1110#if defined(__WIN95__)
1111 if (!(lpPos->flags & SWP_NOSIZE))
1112 {
1113 RECT rectClient;
1114 DWORD dwExStyle = ::GetWindowLong((HWND) GetHWND(), GWL_EXSTYLE);
1115 DWORD dwStyle = ::GetWindowLong((HWND) GetHWND(), GWL_STYLE);
1116 if (ResetWindowStyle((void *) & rectClient) && (dwStyle & WS_MAXIMIZE))
1117 {
1118 ::AdjustWindowRectEx(&rectClient, dwStyle, FALSE, dwExStyle);
1119 lpPos->x = rectClient.left;
1120 lpPos->y = rectClient.top;
1121 lpPos->cx = rectClient.right - rectClient.left;
1122 lpPos->cy = rectClient.bottom - rectClient.top;
1123 }
1124 wxMDIParentFrame* pFrameWnd = (wxMDIParentFrame *)GetParent();
1125 if (pFrameWnd && pFrameWnd->GetToolBar())
1126 {
1127 pFrameWnd->GetToolBar()->Refresh();
1128 }
1129 }
1130#endif
1131 Default();
1132}
1133
1134// Client window
1135wxMDIClientWindow::wxMDIClientWindow(void)
1136{
1137 m_scrollX = 0;
1138 m_scrollY = 0;
1139}
1140
1141wxMDIClientWindow::~wxMDIClientWindow(void)
1142{
1143}
1144
1145bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, const long style)
1146{
1147 m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE);
1148
1149 CLIENTCREATESTRUCT ccs;
1150 m_windowStyle = style;
1151 m_windowParent = parent;
1152
1153 ccs.hWindowMenu = (HMENU) parent->GetWindowMenu();
1154 ccs.idFirstChild = wxFIRST_MDI_CHILD;
1155
1156 DWORD msStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN ;
1157 if ( parent->GetWindowStyleFlag() & wxHSCROLL )
1158 msStyle |= WS_HSCROLL;
1159 if ( parent->GetWindowStyleFlag() & wxVSCROLL )
1160 msStyle |= WS_VSCROLL ;
1161
1162#if defined(__WIN95__)
1163 DWORD exStyle = WS_EX_CLIENTEDGE;
1164#else
1165 DWORD exStyle = 0;
1166#endif
1167
1168 wxWndHook = this;
1169 m_hWnd = (WXHWND) ::CreateWindowEx(exStyle, "mdiclient", NULL,
1170 msStyle, 0, 0, 0, 0, (HWND) parent->GetHWND(), NULL,
1171 wxGetInstance(), (LPSTR)(LPCLIENTCREATESTRUCT)&ccs);
1172 SubclassWin(m_hWnd);
1173 wxWndHook = NULL;
1174
1175 return (m_hWnd != 0) ;
1176}
1177
1178// Window procedure: here for debugging purposes
1179long wxMDIClientWindow::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
1180{
1181 return wxWindow::MSWWindowProc(nMsg, wParam, lParam);
1182// return MSWDefWindowProc(nMsg, wParam, lParam);
1183}
1184
1185long wxMDIClientWindow::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
1186{
1187 if ( MSWGetOldWndProc() != 0)
1188 return ::CallWindowProc(CASTWNDPROC (FARPROC) MSWGetOldWndProc(), (HWND) GetHWND(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
1189 else
1190 return ::DefWindowProc((HWND) m_hWnd, (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
1191}
1192
1193// Explicitly call default scroll behaviour
1194void wxMDIClientWindow::OnScroll(wxScrollEvent& event)
1195{
1196 // Note: for client windows, the scroll position is not set in
1197 // WM_HSCROLL, WM_VSCROLL, so we can't easily determine what
1198 // scroll position we're at.
1199 // This makes it hard to paint patterns or bitmaps in the background,
1200 // and have the client area scrollable as well.
1201
1202 if ( event.GetOrientation() == wxHORIZONTAL )
1203 m_scrollX = event.GetPosition(); // Always returns zero!
1204 else
1205 m_scrollY = event.GetPosition(); // Always returns zero!
1206
1207 Default();
1208}
1209
1210// Should hand the message to the default proc
1211long wxMDIClientWindow::MSWOnMDIActivate(const long bActivate, const WXHWND, const WXHWND)
1212{
1213 return Default();
1214}
1215