1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: MDI classes
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "mdi.h"
18 #include "wx/settings.h"
21 #include <Xm/BulletinB.h>
24 #include <Xm/RowColumn.h>
25 #include <Xm/CascadeBG.h>
27 #include <Xm/PushBG.h>
28 #include <Xm/AtomMgr.h>
29 #include <Xm/Protocols.h>
31 #include "mdi/lib/XsMDICanvas.h"
32 #include "mdi/lib/XsMotifWindow.h"
34 #include "wx/motif/private.h"
36 extern wxList wxModelessWindows
;
38 // Implemented in frame.cpp
39 extern void wxFrameFocusProc(Widget workArea
, XtPointer clientData
,
40 XmAnyCallbackStruct
*cbs
);
42 #if !USE_SHARED_LIBRARY
43 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame
, wxFrame
)
44 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame
, wxFrame
)
45 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow
, wxWindow
)
47 BEGIN_EVENT_TABLE(wxMDIParentFrame
, wxFrame
)
48 EVT_SIZE(wxMDIParentFrame::OnSize
)
49 EVT_ACTIVATE(wxMDIParentFrame::OnActivate
)
50 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged
)
53 BEGIN_EVENT_TABLE(wxMDIClientWindow
, wxWindow
)
54 EVT_SCROLL(wxMDIClientWindow::OnScroll
)
60 static void _doNothingCallback (Widget, XtPointer, XtPointer)
65 // wxXsMDIWindow represents the MDI child frame, as far as the MDI
66 // package is concerned.
67 // TODO: override raise, so we can tell which is the 'active'
68 // (raised) window. We can also use it to send wxActivateEvents,
69 // and switching menubars when we make the child frame menubar
70 // appear on the parent frame.
72 // Note: see XsMotifWindow.C, _XsMotifMenu::_processItem for
73 // where user menu selections are processed.
74 // When Close is selected, _win->close() is called.
76 class wxXsMDIWindow
: public XsMotifWindow
79 wxMDIChildFrame
* m_childFrame
;
81 wxXsMDIWindow(const char* name
, wxMDIChildFrame
* frame
): XsMotifWindow(name
)
85 virtual void setSize(Dimension w
, Dimension h
)
87 XsMotifWindow::setSize(w
, h
);
89 // Generate wxSizeEvent here, I think. Maybe also restore, maximize
90 // Probably don't need to generate size event here since work area
92 wxSizeEvent
event(wxSize(w
, h
), m_childFrame
->GetId());
93 event
.SetEventObject(m_childFrame
);
94 m_childFrame
->ProcessEvent(event
);
98 XsMotifWindow::close();
99 m_childFrame
->Close();
103 XsMotifWindow::raise();
104 m_childFrame
->OnRaise();
108 XsMotifWindow::lower();
109 m_childFrame
->OnLower();
111 virtual void _buildClientArea(Widget parent
)
113 m_childFrame
->BuildClientArea((WXWidget
) parent
);
115 // Code from MDI sample
117 assert (parent
!= 0);
123 // Create a main window with some dummy menus
125 Widget mainW
= XtVaCreateWidget ("mainWin", xmMainWindowWidgetClass
, parent
,
126 XmNtopAttachment
, XmATTACH_FORM
, XmNbottomAttachment
, XmATTACH_FORM
,
127 XmNleftAttachment
, XmATTACH_FORM
, XmNrightAttachment
, XmATTACH_FORM
,
132 Widget menuBar
= XmCreateMenuBar (mainW
, "menuBar", NULL
, 0);
134 // Create the "file" menu
136 pulldown
= XmCreatePulldownMenu (menuBar
, "pulldown", NULL
, 0);
137 cascade
= XtVaCreateManagedWidget ("fileMenu", xmCascadeButtonGadgetClass
,
138 menuBar
, XmNsubMenuId
, pulldown
, NULL
);
140 button
= XtVaCreateManagedWidget ("openMenuItem", xmPushButtonGadgetClass
,
142 XtAddCallback (button
, XmNactivateCallback
, _doNothingCallback
, (XtPointer
)this);
144 button
= XtVaCreateManagedWidget ("newMenuItem", xmPushButtonGadgetClass
,
146 // XtAddCallback (button, XmNactivateCallback, _newWindowCallback, (XtPointer)this);
148 // Create the "edit" menu
150 pulldown
= XmCreatePulldownMenu (menuBar
, "pulldown", NULL
, 0);
151 cascade
= XtVaCreateManagedWidget ("editMenu", xmCascadeButtonGadgetClass
,
152 menuBar
, XmNsubMenuId
, pulldown
, NULL
);
154 button
= XtVaCreateManagedWidget ("cutMenuItem", xmPushButtonGadgetClass
,
156 XtAddCallback (button
, XmNactivateCallback
, _doNothingCallback
, (XtPointer
)this);
158 button
= XtVaCreateManagedWidget ("copyMenuItem", xmPushButtonGadgetClass
,
160 XtAddCallback (button
, XmNactivateCallback
, _doNothingCallback
, (XtPointer
)this);
162 button
= XtVaCreateManagedWidget ("pasteMenuItem", xmPushButtonGadgetClass
,
164 XtAddCallback (button
, XmNactivateCallback
, _doNothingCallback
, (XtPointer
)this);
166 // Create the help menu
168 pulldown
= XmCreatePulldownMenu (menuBar
, "pulldown", NULL
, 0);
169 cascade
= XtVaCreateManagedWidget ("helpMenu", xmCascadeButtonGadgetClass
,
170 menuBar
, XmNsubMenuId
, pulldown
, NULL
);
172 button
= XtVaCreateManagedWidget ("aboutMenuItem", xmPushButtonGadgetClass
,
174 XtAddCallback (button
, XmNactivateCallback
, _doNothingCallback
, (XtPointer
)this);
176 XtVaSetValues (menuBar
, XmNmenuHelpWidget
, cascade
, NULL
);
178 // Manage the menubar
180 XtManageChild (menuBar
);
182 // Create the work area
189 XtSetArg (args
[n
], XmNscrollingPolicy
, XmAUTOMATIC
); n
++;
190 XtSetArg (args
[n
], XmNhighlightThickness
, (Dimension
)0); n
++;
191 XtSetArg (args
[n
], XmNeditMode
, XmMULTI_LINE_EDIT
); n
++;
192 XtSetArg (args
[n
], XmNeditable
, True
); n
++;
193 XtSetArg (args
[n
], XmNwordWrap
, False
); n
++;
194 XtSetArg (args
[n
], XmNcursorPositionVisible
, True
); n
++;
195 XtSetArg (args
[n
], XmNverifyBell
, True
); n
++;
199 Widget scrolledText
= XmCreateScrolledText (mainW
, "scrolledText", args
, n
);
200 XtManageChild (scrolledText
);
202 // Set the main window area
204 XtVaSetValues (mainW
, XmNmenuBar
, menuBar
, XmNworkWindow
,
205 XtParent (scrolledText
), NULL
);
207 XtManageChild (mainW
);
210 void Show() { show(); }
215 wxMDIParentFrame::wxMDIParentFrame()
217 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
218 m_activeChild
= (wxMDIChildFrame
*) NULL
;
221 bool wxMDIParentFrame::Create(wxWindow
*parent
,
223 const wxString
& title
,
227 const wxString
& name
)
229 m_clientWindow
= (wxMDIClientWindow
*) NULL
;
230 m_activeChild
= (wxMDIChildFrame
*) NULL
;
232 bool success
= wxFrame::Create(parent
, id
, title
, pos
, size
, style
, name
);
235 // TODO: app cannot override OnCreateClient since
236 // wxMDIParentFrame::OnCreateClient will still be called
237 // (we're in the constructor). How to resolve?
239 m_clientWindow
= OnCreateClient();
240 // Uses own style for client style
241 m_clientWindow
->CreateClient(this, GetWindowStyleFlag());
248 wxMDIParentFrame::~wxMDIParentFrame()
251 delete m_clientWindow
;
254 // Get size *available for subwindows* i.e. excluding menu bar.
255 void wxMDIParentFrame::GetClientSize(int *x
, int *y
) const
257 wxFrame::GetClientSize(x
, y
);
260 void wxMDIParentFrame::SetMenuBar(wxMenuBar
*menu_bar
)
262 wxFrame::SetMenuBar(menu_bar
);
265 void wxMDIParentFrame::OnSize(wxSizeEvent
& event
)
267 #if wxUSE_CONSTRAINTS
274 GetClientSize(&width
, &height
);
276 if ( GetClientWindow() )
277 GetClientWindow()->SetSize(x
, y
, width
, height
);
280 void wxMDIParentFrame::OnActivate(wxActivateEvent
& event
)
285 // Returns the active MDI child window
286 wxMDIChildFrame
*wxMDIParentFrame::GetActiveChild() const
288 return m_activeChild
;
291 // Create the client window class (don't Create the window,
292 // just return a new class)
293 wxMDIClientWindow
*wxMDIParentFrame::OnCreateClient()
295 return new wxMDIClientWindow
;
298 // Responds to colour changes, and passes event on to children.
299 void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
303 // Propagate the event to the non-top-level children
304 wxFrame::OnSysColourChanged(event
);
308 void wxMDIParentFrame::Cascade()
313 void wxMDIParentFrame::Tile()
318 void wxMDIParentFrame::ArrangeIcons()
323 void wxMDIParentFrame::ActivateNext()
328 void wxMDIParentFrame::ActivatePrevious()
335 wxMDIChildFrame::wxMDIChildFrame()
339 bool wxMDIChildFrame::Create(wxMDIParentFrame
*parent
,
341 const wxString
& title
,
345 const wxString
& name
)
352 m_windowId
= (int)NewControlId();
354 if (parent
) parent
->AddChild(this);
356 int x
= pos
.x
; int y
= pos
.y
;
357 int width
= size
.x
; int height
= size
.y
;
359 width
= 200; // TODO: give reasonable default
361 height
= 200; // TODO: give reasonable default
363 wxMDIClientWindow
* clientWindow
= parent
->GetClientWindow();
367 // We're deactivating the old child
368 wxMDIChildFrame
* oldActiveChild
= parent
->GetActiveChild();
371 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, oldActiveChild
->GetId());
372 event
.SetEventObject( oldActiveChild
);
373 oldActiveChild
->GetEventHandler()->ProcessEvent(event
);
376 m_mdiWindow
= new wxXsMDIWindow("mdiChildWindow", this);
377 clientWindow
->GetMDICanvas()->add(m_mdiWindow
);
379 // This is the currently active child
380 parent
->SetActiveChild((wxMDIChildFrame
*) this);
385 m_mainWidget
= (WXWidget
) (Widget
) (*m_mdiWindow
);
387 m_frameWidget
= (WXWidget
) XtVaCreateManagedWidget("main_window",
388 xmMainWindowWidgetClass
, (Widget
) m_mainWidget
,
389 XmNresizePolicy
, XmRESIZE_NONE
,
392 m_workArea
= (WXWidget
) XtVaCreateWidget("form",
393 xmFormWidgetClass
, (Widget
) m_frameWidget
,
394 XmNresizePolicy
, XmRESIZE_NONE
,
397 m_clientArea
= (WXWidget
) XtVaCreateWidget("client",
398 xmBulletinBoardWidgetClass
, (Widget
) m_workArea
,
401 XmNrightAttachment
, XmATTACH_FORM
,
402 XmNleftAttachment
, XmATTACH_FORM
,
403 XmNtopAttachment
, XmATTACH_FORM
,
404 XmNbottomAttachment
, XmATTACH_FORM
,
405 // XmNresizePolicy, XmRESIZE_ANY,
408 XtVaSetValues((Widget
) m_frameWidget
,
409 XmNworkWindow
, (Widget
) m_workArea
,
412 XtManageChild((Widget
) m_clientArea
);
413 XtManageChild((Widget
) m_workArea
);
415 wxASSERT_MSG ((wxWidgetHashTable
->Get((long)m_workArea
) == (wxObject
*) NULL
), "Widget table clash in frame.cpp") ;
417 wxAddWindowToTable((Widget
) m_workArea
, this);
421 XtOverrideTranslations((Widget
) m_workArea
,
422 ptr
= XtParseTranslationTable("<Configure>: resize()"));
426 XtAddCallback((Widget
) m_workArea
, XmNfocusCallback
,
427 (XtCallbackProc
)wxFrameFocusProc
, (XtPointer
)this);
430 XtVaSetValues((Widget
) m_mainWidget
, XmNx
, x
, NULL
);
432 XtVaSetValues((Widget
) m_mainWidget
, XmNy
, y
, NULL
);
434 XtVaSetValues((Widget
) m_mainWidget
, XmNwidth
, width
, NULL
);
436 XtVaSetValues((Widget
) m_mainWidget
, XmNheight
, height
, NULL
);
443 m_mdiWindow
->setSize(width
, height
);
445 wxModelessWindows
.Append(this);
449 void wxMDIChildFrame::BuildClientArea(WXWidget parent
)
451 m_mainWidget
= parent
;
453 m_frameWidget
= (WXWidget
) XtVaCreateManagedWidget("main_window",
454 xmMainWindowWidgetClass
, (Widget
) m_mainWidget
,
455 XmNresizePolicy
, XmRESIZE_NONE
,
456 XmNtopAttachment
, XmATTACH_FORM
,
457 XmNbottomAttachment
, XmATTACH_FORM
,
458 XmNleftAttachment
, XmATTACH_FORM
,
459 XmNrightAttachment
, XmATTACH_FORM
,
462 m_workArea
= (WXWidget
) XtVaCreateWidget("form",
463 xmFormWidgetClass
, (Widget
) m_frameWidget
,
464 XmNresizePolicy
, XmRESIZE_NONE
,
467 m_clientArea
= (WXWidget
) XtVaCreateWidget("client",
468 xmBulletinBoardWidgetClass
, (Widget
) m_workArea
,
471 XmNrightAttachment
, XmATTACH_FORM
,
472 XmNleftAttachment
, XmATTACH_FORM
,
473 XmNtopAttachment
, XmATTACH_FORM
,
474 XmNbottomAttachment
, XmATTACH_FORM
,
475 // XmNresizePolicy, XmRESIZE_ANY,
478 XtVaSetValues((Widget
) m_frameWidget
,
479 XmNworkWindow
, (Widget
) m_workArea
,
482 XtManageChild((Widget
) m_clientArea
);
483 XtManageChild((Widget
) m_workArea
);
485 wxASSERT_MSG ((wxWidgetHashTable
->Get((long)m_workArea
) == (wxObject
*) NULL
), "Widget table clash in frame.cpp") ;
487 wxAddWindowToTable((Widget
) m_workArea
, this);
491 XtOverrideTranslations((Widget
) m_workArea
,
492 ptr
= XtParseTranslationTable("<Configure>: resize()"));
496 XtAddCallback((Widget
) m_workArea
, XmNfocusCallback
,
497 (XtCallbackProc
)wxFrameFocusProc
, (XtPointer
)this);
500 int x = pos.x; int y = pos.y;
501 int width = size.x; int height = size.y;
504 XtVaSetValues((Widget) m_mainWidget, XmNx, x, NULL);
506 XtVaSetValues((Widget) m_mainWidget, XmNy, y, NULL);
508 XtVaSetValues((Widget) m_mainWidget, XmNwidth, width, NULL);
510 XtVaSetValues((Widget) m_mainWidget, XmNheight, height, NULL);
513 XtManageChild((Widget
) m_frameWidget
);
517 wxMDIChildFrame::~wxMDIChildFrame()
519 wxMDIParentFrame
* parentFrame
= (wxMDIParentFrame
*) GetParent() ;
520 if (parentFrame
->GetActiveChild() == this)
521 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
523 wxMDIClientWindow
* clientWindow
= parentFrame
->GetClientWindow();
524 clientWindow
->GetMDICanvas()->remove(m_mdiWindow
);
525 m_mainWidget
= (WXWidget
) 0;
528 // Implementation: intercept and act upon raise and lower commands.
529 void wxMDIChildFrame::OnRaise()
531 wxMDIParentFrame
* parentFrame
= (wxMDIParentFrame
*) GetParent() ;
532 wxMDIChildFrame
* oldActiveChild
= parentFrame
->GetActiveChild();
533 parentFrame
->SetActiveChild(this);
537 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, oldActiveChild
->GetId());
538 event
.SetEventObject( oldActiveChild
);
539 oldActiveChild
->GetEventHandler()->ProcessEvent(event
);
542 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, this->GetId());
543 event
.SetEventObject( this );
544 this->GetEventHandler()->ProcessEvent(event
);
547 void wxMDIChildFrame::OnLower()
549 wxMDIParentFrame
* parentFrame
= (wxMDIParentFrame
*) GetParent() ;
550 wxMDIChildFrame
* oldActiveChild
= parentFrame
->GetActiveChild();
552 if (oldActiveChild
== this)
554 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, oldActiveChild
->GetId());
555 event
.SetEventObject( oldActiveChild
);
556 oldActiveChild
->GetEventHandler()->ProcessEvent(event
);
558 // TODO: unfortunately we don't now know which is the top-most child,
559 // so make the active child NULL.
560 parentFrame
->SetActiveChild((wxMDIChildFrame
*) NULL
);
563 // Set the client size (i.e. leave the calculation of borders etc.
565 void wxMDIChildFrame::SetClientSize(int width
, int height
)
567 wxFrame::SetClientSize(width
, height
);
570 void wxMDIChildFrame::GetClientSize(int* width
, int* height
) const
572 wxFrame::GetClientSize(width
, height
);
575 void wxMDIChildFrame::SetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
577 wxWindow::SetSize(x
, y
, width
, height
, sizeFlags
);
580 void wxMDIChildFrame::GetSize(int* width
, int* height
) const
582 wxWindow::GetSize(width
, height
);
585 void wxMDIChildFrame::GetPosition(int *x
, int *y
) const
587 wxWindow::GetPosition(x
, y
);
590 bool wxMDIChildFrame::Show(bool show
)
592 m_visibleStatus
= show
; /* show-&-hide fix */
596 void wxMDIChildFrame::SetMenuBar(wxMenuBar
*menu_bar
)
599 // Currently, the menu appears on the child frame.
600 // It should eventually be recreated on the main frame
601 // whenever the child is activated.
602 wxFrame::SetMenuBar(menu_bar
);
606 void wxMDIChildFrame::SetIcon(const wxIcon
& icon
)
611 /* TODO: doesn't work yet (crashes in XCopyArea)
612 Pixmap pixmap = (Pixmap) m_icon.GetPixmap();
613 m_mdiWindow->setPixmap(pixmap);
618 void wxMDIChildFrame::SetTitle(const wxString
& title
)
621 m_mdiWindow
->setTitle(title
);
622 m_mdiWindow
->setIconName(title
);
626 void wxMDIChildFrame::Maximize()
628 m_mdiWindow
->maximize();
631 void wxMDIChildFrame::Iconize(bool iconize
)
634 m_mdiWindow
->minimize();
636 m_mdiWindow
->restore();
639 bool wxMDIChildFrame::IsIconized() const
641 return m_mdiWindow
->minimized();
644 void wxMDIChildFrame::Restore()
646 m_mdiWindow
->restore();
649 void wxMDIChildFrame::Activate()
651 m_mdiWindow
->raise();
656 wxMDIClientWindow::wxMDIClientWindow()
659 m_topWidget
= (WXWidget
) 0;
662 wxMDIClientWindow::~wxMDIClientWindow()
667 m_mainWidget
= (WXWidget
) 0;
668 m_topWidget
= (WXWidget
) 0;
671 bool wxMDIClientWindow::CreateClient(wxMDIParentFrame
*parent
, long style
)
673 m_windowParent
= parent
;
674 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
);
675 m_mdiCanvas
= new XsMDICanvas("mdiClientWindow", (Widget
) parent
->GetClientWidget());
676 m_mainWidget
= (WXWidget
) m_mdiCanvas
->GetDrawingArea();
677 // m_topWidget = (WXWidget) m_mdiCanvas->GetBase();
678 m_topWidget
= (WXWidget
) (Widget
) (*m_mdiCanvas
);
685 void wxMDIClientWindow::SetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
687 wxWindow::SetSize(x
, y
, width
, height
, sizeFlags
);
690 void wxMDIClientWindow::SetClientSize(int width
, int height
)
692 wxWindow::SetClientSize(width
, height
);
695 void wxMDIClientWindow::GetClientSize(int *width
, int *height
) const
697 wxWindow::GetClientSize(width
, height
);
700 void wxMDIClientWindow::GetSize(int *width
, int *height
) const
702 wxWindow::GetSize(width
, height
);
705 void wxMDIClientWindow::GetPosition(int *x
, int *y
) const
707 wxWindow::GetPosition(x
, y
);
710 // Explicitly call default scroll behaviour
711 void wxMDIClientWindow::OnScroll(wxScrollEvent
& event
)
713 Default(); // Default processing