1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/mdi.cpp
3 // Purpose: MDI classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
16 #define XtDisplay XTDISPLAY
17 #define XtWindow XTWINDOW
25 #include "wx/settings.h"
29 #pragma message disable nosimpint
32 #include <Xm/BulletinB.h>
35 #include <Xm/RowColumn.h>
36 #include <Xm/CascadeBG.h>
38 #include <Xm/PushBG.h>
39 #include <Xm/AtomMgr.h>
40 #include <Xm/Protocols.h>
42 #pragma message enable nosimpint
45 #include "wx/motif/private.h"
47 extern wxList wxModelessWindows
;
49 // Implemented in frame.cpp
50 extern void wxFrameFocusProc(Widget workArea
, XtPointer clientData
,
51 XmAnyCallbackStruct
*cbs
);
53 #define wxID_NOTEBOOK_CLIENT_AREA wxID_HIGHEST + 100
55 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
)
56 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
)
57 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxNotebook
)
59 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
)
60 EVT_SIZE(wxMDIParentFrame::OnSize
)
61 EVT_ACTIVATE(wxMDIParentFrame::OnActivate
)
62 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
)
63 EVT_MENU_HIGHLIGHT_ALL(wxMDIParentFrame::OnMenuHighlight
)
66 BEGIN_EVENT_TABLE(wxMDIClientWindow
, wxNotebook
)
67 EVT_SCROLL(wxMDIClientWindow::OnScroll
)
68 EVT_NOTEBOOK_PAGE_CHANGED(wxID_NOTEBOOK_CLIENT_AREA
, wxMDIClientWindow::OnPageChanged
)
74 wxMDIParentFrame::wxMDIParentFrame()
76 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
77 m_activeChild
= (wxMDIChildFrame
*) NULL
;
78 m_activeMenuBar
= (wxMenuBar
*) NULL
;
81 bool wxMDIParentFrame::Create(wxWindow
*parent
,
83 const wxString
& title
,
89 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
90 m_activeChild
= (wxMDIChildFrame
*) NULL
;
91 m_activeMenuBar
= (wxMenuBar
*) NULL
;
93 bool success
= wxFrame::Create(parent
, id
, title
, pos
, size
, style
, name
);
96 // TODO: app cannot override OnCreateClient since
97 // wxMDIParentFrame::OnCreateClient will still be called
98 // (we're in the constructor). How to resolve?
100 m_clientWindow
= OnCreateClient();
102 // Uses own style for client style
103 m_clientWindow
->CreateClient(this, GetWindowStyleFlag());
106 GetClientSize(& w
, & h
);
107 m_clientWindow
->SetSize(0, 0, w
, h
);
114 wxMDIParentFrame::~wxMDIParentFrame()
116 // Make sure we delete the client window last of all
117 RemoveChild(m_clientWindow
);
121 delete m_clientWindow
;
122 m_clientWindow
= NULL
;
125 void wxMDIParentFrame::SetMenuBar(wxMenuBar
*menu_bar
)
127 m_frameMenuBar
= menu_bar
;
129 SetChildMenuBar((wxMDIChildFrame
*) NULL
);
132 void wxMDIParentFrame::OnSize(wxSizeEvent
& WXUNUSED(event
))
134 #if wxUSE_CONSTRAINTS
141 GetClientSize(&width
, &height
);
143 if ( GetClientWindow() )
144 GetClientWindow()->SetSize(x
, y
, width
, height
);
147 void wxMDIParentFrame::DoGetClientSize(int *width
, int *height
) const
149 wxFrame::DoGetClientSize(width
, height
);
152 void wxMDIParentFrame::OnActivate(wxActivateEvent
& WXUNUSED(event
))
157 // Returns the active MDI child window
158 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
160 return m_activeChild
;
163 // Create the client window class (don't Create the window,
164 // just return a new class)
165 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
167 return new wxMDIClientWindow
;
170 // Set the child's menu into the parent frame
171 void wxMDIParentFrame::SetChildMenuBar(wxMDIChildFrame
* child
)
173 wxMenuBar
* oldMenuBar
= m_activeMenuBar
;
175 if (child
== (wxMDIChildFrame
*) NULL
) // No child: use parent frame
177 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar
))
179 // if (m_activeMenuBar)
180 // m_activeMenuBar->DestroyMenuBar();
182 m_activeMenuBar
= GetMenuBar();
183 m_activeMenuBar
->CreateMenuBar(this);
185 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
186 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
188 if (oldMenuBar
&& oldMenuBar
->GetMainWidget())
189 XtUnmapWidget((Widget
) oldMenuBar
->GetMainWidget());
193 else if (child
->GetMenuBar() == (wxMenuBar
*) NULL
) // No child menu bar: use parent frame
195 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar
))
197 // if (m_activeMenuBar)
198 // m_activeMenuBar->DestroyMenuBar();
199 m_activeMenuBar
= GetMenuBar();
200 m_activeMenuBar
->CreateMenuBar(this);
202 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
203 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
205 if (oldMenuBar
&& oldMenuBar
->GetMainWidget())
206 XtUnmapWidget((Widget
) oldMenuBar
->GetMainWidget());
209 else // The child has a menubar
211 if (child
->GetMenuBar() != m_activeMenuBar
)
213 // if (m_activeMenuBar)
214 // m_activeMenuBar->DestroyMenuBar();
216 m_activeMenuBar
= child
->GetMenuBar();
217 m_activeMenuBar
->CreateMenuBar(this);
219 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
220 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
222 if (oldMenuBar
&& oldMenuBar
->GetMainWidget())
223 XtUnmapWidget((Widget
) oldMenuBar
->GetMainWidget());
228 // Redirect events to active child first
229 bool wxMDIParentFrame::ProcessEvent(wxEvent
& event
)
231 // Stops the same event being processed repeatedly
232 static wxEventType inEvent
= wxEVT_NULL
;
233 if (inEvent
== event
.GetEventType())
236 inEvent
= event
.GetEventType();
239 if (m_activeChild
&& event
.IsKindOf(CLASSINFO(wxCommandEvent
)))
241 res
= m_activeChild
->GetEventHandler()->ProcessEvent(event
);
245 res
= GetEventHandler()->wxEvtHandler::ProcessEvent(event
);
247 inEvent
= wxEVT_NULL
;
252 void wxMDIParentFrame::DoSetSize(int x
, int y
,
253 int width
, int height
,
256 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
259 void wxMDIParentFrame::DoSetClientSize(int width
, int height
)
261 wxWindow::DoSetClientSize(width
, height
);
264 // Responds to colour changes, and passes event on to children.
265 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
269 // Propagate the event to the non-top-level children
270 wxFrame::OnSysColourChanged(event
);
274 void wxMDIParentFrame::Cascade()
279 void wxMDIParentFrame::Tile(wxOrientation
WXUNUSED(orient
))
284 void wxMDIParentFrame::ArrangeIcons()
289 void wxMDIParentFrame::ActivateNext()
294 void wxMDIParentFrame::ActivatePrevious()
299 // Default menu selection behaviour - display a help string
300 void wxMDIParentFrame::OnMenuHighlight(wxMenuEvent
& event
)
304 if (event
.GetMenuId() == -1)
305 SetStatusText(wxEmptyString
);
308 wxMenuBar
*menuBar
= (wxMenuBar
*) NULL
;
309 if (GetActiveChild())
310 menuBar
= GetActiveChild()->GetMenuBar();
312 menuBar
= GetMenuBar();
315 wxString
helpString(menuBar
->GetHelpString(event
.GetMenuId()));
316 if (!helpString
.empty())
317 SetStatusText(helpString
);
325 wxMDIChildFrame::wxMDIChildFrame()
327 m_mdiParentFrame
= (wxMDIParentFrame
*) NULL
;
330 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
332 const wxString
& title
,
336 const wxString
& name
)
339 SetWindowStyleFlag(style
);
341 m_backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE
);
342 m_foregroundColour
= *wxBLACK
;
343 m_font
= wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
);
348 m_windowId
= (int)NewControlId();
350 wxMDIClientWindow
* clientWindow
= parent
->GetClientWindow();
352 wxCHECK_MSG( clientWindow
, false, "Missing MDI client window." );
354 clientWindow
->AddChild(this);
356 SetMDIParentFrame(parent
);
361 width
= 200; // TODO: give reasonable default
363 height
= 200; // TODO: give reasonable default
365 // We're deactivating the old child
366 wxMDIChildFrame
* oldActiveChild
= parent
->GetActiveChild();
369 wxActivateEvent
event(wxEVT_ACTIVATE
, false, oldActiveChild
->GetId());
370 event
.SetEventObject( oldActiveChild
);
371 oldActiveChild
->GetEventHandler()->ProcessEvent(event
);
374 // This is the currently active child
375 parent
->SetActiveChild((wxMDIChildFrame
*) this);
377 // This time we'll try a bog-standard bulletin board for
378 // the 'frame'. A main window doesn't seem to work.
380 m_mainWidget
= (WXWidget
) XtVaCreateWidget("client",
381 xmBulletinBoardWidgetClass
, (Widget
) clientWindow
->GetTopWidget(),
385 XmNrightAttachment, XmATTACH_FORM,
386 XmNleftAttachment, XmATTACH_FORM,
387 XmNtopAttachment, XmATTACH_FORM,
388 XmNbottomAttachment, XmATTACH_FORM,
390 XmNresizePolicy
, XmRESIZE_NONE
,
393 XtAddEventHandler((Widget
) m_mainWidget
, ExposureMask
,False
,
394 wxUniversalRepaintProc
, (XtPointer
) this);
396 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, size
.x
, size
.y
);
398 ChangeBackgroundColour();
400 XtManageChild((Widget
) m_mainWidget
);
404 clientWindow
->AddPage(this, title
, true);
405 clientWindow
->Refresh();
407 // Positions the toolbar and status bar -- but we don't have any.
410 wxModelessWindows
.Append(this);
415 wxMDIChildFrame::~wxMDIChildFrame()
418 XtRemoveEventHandler((Widget
) m_mainWidget
, ExposureMask
,False
,
419 wxUniversalRepaintProc
, (XtPointer
) this);
421 if (GetMDIParentFrame())
423 wxMDIParentFrame
* parentFrame
= GetMDIParentFrame();
425 if (parentFrame
->GetActiveChild() == this)
426 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
427 wxMDIClientWindow
* clientWindow
= parentFrame
->GetClientWindow();
429 // Remove page if still there
431 int i
= clientWindow
->FindPage(this);
435 clientWindow
->RemovePage(i
);
436 clientWindow
->Refresh();
440 // Set the selection to the first remaining page
441 if (clientWindow
->GetPageCount() > 0)
443 wxMDIChildFrame
* child
= (wxMDIChildFrame
*) clientWindow
->GetPage(0);
444 parentFrame
->SetActiveChild(child
);
445 parentFrame
->SetChildMenuBar(child
);
449 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
450 parentFrame
->SetChildMenuBar((wxMDIChildFrame
*) NULL
);
456 // Implementation: intercept and act upon raise and lower commands.
457 void wxMDIChildFrame::OnRaise()
459 wxMDIParentFrame
* parentFrame
= (wxMDIParentFrame
*) GetParent() ;
460 wxMDIChildFrame
* oldActiveChild
= parentFrame
->GetActiveChild();
461 parentFrame
->SetActiveChild(this);
465 wxActivateEvent
event(wxEVT_ACTIVATE
, false, oldActiveChild
->GetId());
466 event
.SetEventObject( oldActiveChild
);
467 oldActiveChild
->GetEventHandler()->ProcessEvent(event
);
470 wxActivateEvent
event(wxEVT_ACTIVATE
, true, this->GetId());
471 event
.SetEventObject( this );
472 this->GetEventHandler()->ProcessEvent(event
);
475 void wxMDIChildFrame::OnLower()
477 wxMDIParentFrame
* parentFrame
= (wxMDIParentFrame
*) GetParent() ;
478 wxMDIChildFrame
* oldActiveChild
= parentFrame
->GetActiveChild();
480 if (oldActiveChild
== this)
482 wxActivateEvent
event(wxEVT_ACTIVATE
, false, oldActiveChild
->GetId());
483 event
.SetEventObject( oldActiveChild
);
484 oldActiveChild
->GetEventHandler()->ProcessEvent(event
);
486 // TODO: unfortunately we don't now know which is the top-most child,
487 // so make the active child NULL.
488 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
492 // Set the client size (i.e. leave the calculation of borders etc.
494 void wxMDIChildFrame::DoSetClientSize(int width
, int height
)
496 wxWindow::DoSetClientSize(width
, height
);
499 void wxMDIChildFrame::DoGetClientSize(int* width
, int* height
) const
501 wxWindow::DoGetSize(width
, height
);
504 void wxMDIChildFrame::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
506 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
509 void wxMDIChildFrame::DoGetSize(int* width
, int* height
) const
511 wxWindow::DoGetSize(width
, height
);
514 void wxMDIChildFrame::DoGetPosition(int *x
, int *y
) const
516 wxWindow::DoGetPosition(x
, y
);
519 bool wxMDIChildFrame::Show(bool show
)
521 SetVisibleStatus( show
);
522 return wxWindow::Show(show
);
525 void wxMDIChildFrame::SetMenuBar(wxMenuBar
*menuBar
)
527 // Don't create the underlying menubar yet; need to recreate
528 // it every time the child is activated.
529 m_frameMenuBar
= menuBar
;
531 // We make the assumption that if you're setting the menubar,
532 // this is the currently active child.
533 GetMDIParentFrame()->SetChildMenuBar(this);
537 void wxMDIChildFrame::SetIcon(const wxIcon
& icon
)
539 m_icons
= wxIconBundle( icon
);
543 // Not appropriate since there are no icons in
548 void wxMDIChildFrame::SetIcons(const wxIconBundle
& icons
)
553 void wxMDIChildFrame::SetTitle(const wxString
& title
)
555 wxTopLevelWindow::SetTitle( title
);
556 wxMDIClientWindow
* clientWindow
= GetMDIParentFrame()->GetClientWindow();
558 // Remove page if still there
560 int i
= clientWindow
->FindPage(this);
563 clientWindow
->SetPageText(i
, title
);
568 void wxMDIChildFrame::Maximize()
573 void wxMDIChildFrame::Iconize(bool WXUNUSED(iconize
))
578 bool wxMDIChildFrame::IsIconized() const
583 // Is it maximized? Always maximized under Motif, using the
584 // tabbed MDI implementation.
585 bool wxMDIChildFrame::IsMaximized(void) const
590 void wxMDIChildFrame::Restore()
595 void wxMDIChildFrame::Activate()
600 void wxMDIChildFrame::CaptureMouse()
602 wxWindow::CaptureMouse();
605 void wxMDIChildFrame::ReleaseMouse()
607 wxWindow::ReleaseMouse();
610 void wxMDIChildFrame::Raise()
615 void wxMDIChildFrame::Lower(void)
620 void wxMDIChildFrame::DoSetSizeHints(int WXUNUSED(minW
), int WXUNUSED(minH
), int WXUNUSED(maxW
), int WXUNUSED(maxH
), int WXUNUSED(incW
), int WXUNUSED(incH
))
626 wxMDIClientWindow::wxMDIClientWindow()
630 wxMDIClientWindow::~wxMDIClientWindow()
632 // By the time this destructor is called, the child frames will have been
633 // deleted and removed from the notebook/client window.
636 m_mainWidget
= (WXWidget
) 0;
639 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
641 SetWindowStyleFlag(style
);
643 // m_windowParent = parent;
644 // m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE);
646 bool success
= wxNotebook::Create(parent
, wxID_NOTEBOOK_CLIENT_AREA
, wxPoint(0, 0), wxSize(100, 100), 0);
649 wxFont
font(10, wxSWISS
, wxNORMAL
, wxNORMAL
);
657 int wxMDIClientWindow::FindPage(const wxNotebookPage
* page
)
659 for (int i
= GetPageCount() - 1; i
>= 0; --i
)
661 if (GetPage(i
) == page
)
668 void wxMDIClientWindow::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
670 wxWindow::DoSetSize(x
, y
, width
, height
, sizeFlags
);
673 void wxMDIClientWindow::DoSetClientSize(int width
, int height
)
675 wxWindow::DoSetClientSize(width
, height
);
678 void wxMDIClientWindow::DoGetClientSize(int *width
, int *height
) const
680 wxWindow::DoGetClientSize(width
, height
);
683 void wxMDIClientWindow::DoGetSize(int *width
, int *height
) const
685 wxWindow::DoGetSize(width
, height
);
688 void wxMDIClientWindow::DoGetPosition(int *x
, int *y
) const
690 wxWindow::DoGetPosition(x
, y
);
693 void wxMDIClientWindow::OnScroll(wxScrollEvent
& event
)
695 // Default(); // Default processing: OBSOLETE FUNCTION
699 void wxMDIClientWindow::OnPageChanged(wxNotebookEvent
& event
)
701 // Notify child that it has been activated
702 if (event
.GetOldSelection() != -1)
704 wxMDIChildFrame
* oldChild
= (wxMDIChildFrame
*) GetPage(event
.GetOldSelection());
707 wxActivateEvent
event(wxEVT_ACTIVATE
, false, oldChild
->GetId());
708 event
.SetEventObject( oldChild
);
709 oldChild
->GetEventHandler()->ProcessEvent(event
);
712 if (event
.GetSelection() != -1)
714 wxMDIChildFrame
* activeChild
= (wxMDIChildFrame
*) GetPage(event
.GetSelection());
717 wxActivateEvent
event(wxEVT_ACTIVATE
, true, activeChild
->GetId());
718 event
.SetEventObject( activeChild
);
719 activeChild
->GetEventHandler()->ProcessEvent(event
);
721 if (activeChild
->GetMDIParentFrame())
723 activeChild
->GetMDIParentFrame()->SetActiveChild(activeChild
);
724 activeChild
->GetMDIParentFrame()->SetChildMenuBar(activeChild
);