]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/motif/mdi.cpp
Fix for crash when the child has no menu
[wxWidgets.git] / src / motif / mdi.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: mdi.cpp
3// Purpose: MDI classes
4// Author: Julian Smart
5// Modified by:
6// Created: 17/09/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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 __VMS
20#define XtDisplay XTDISPLAY
21#define XtWindow XTWINDOW
22#endif
23
24#include "wx/mdi.h"
25#include "wx/menu.h"
26#include "wx/settings.h"
27#include "wx/icon.h"
28
29#ifdef __VMS__
30#pragma message disable nosimpint
31#endif
32#include <Xm/Xm.h>
33#include <Xm/BulletinB.h>
34#include <Xm/Form.h>
35#include <Xm/MainW.h>
36#include <Xm/RowColumn.h>
37#include <Xm/CascadeBG.h>
38#include <Xm/Text.h>
39#include <Xm/PushBG.h>
40#include <Xm/AtomMgr.h>
41#include <Xm/Protocols.h>
42#ifdef __VMS__
43#pragma message enable nosimpint
44#endif
45
46#include "wx/motif/private.h"
47
48extern wxList wxModelessWindows;
49
50// Implemented in frame.cpp
51extern void wxFrameFocusProc(Widget workArea, XtPointer clientData,
52 XmAnyCallbackStruct *cbs);
53
54#define wxID_NOTEBOOK_CLIENT_AREA wxID_HIGHEST + 100
55
56IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame)
57IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame)
58IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxNotebook)
59
60BEGIN_EVENT_TABLE(wxMDIParentFrame, wxFrame)
61 EVT_SIZE(wxMDIParentFrame::OnSize)
62 EVT_ACTIVATE(wxMDIParentFrame::OnActivate)
63 EVT_SYS_COLOUR_CHANGED(wxMDIParentFrame::OnSysColourChanged)
64 EVT_MENU_HIGHLIGHT_ALL(wxMDIParentFrame::OnMenuHighlight)
65END_EVENT_TABLE()
66
67BEGIN_EVENT_TABLE(wxMDIClientWindow, wxNotebook)
68 EVT_SCROLL(wxMDIClientWindow::OnScroll)
69 EVT_NOTEBOOK_PAGE_CHANGED(wxID_NOTEBOOK_CLIENT_AREA, wxMDIClientWindow::OnPageChanged)
70END_EVENT_TABLE()
71
72
73// Parent frame
74
75wxMDIParentFrame::wxMDIParentFrame()
76{
77 m_clientWindow = (wxMDIClientWindow*) NULL;
78 m_activeChild = (wxMDIChildFrame*) NULL;
79 m_activeMenuBar = (wxMenuBar*) NULL;
80}
81
82bool wxMDIParentFrame::Create(wxWindow *parent,
83 wxWindowID id,
84 const wxString& title,
85 const wxPoint& pos,
86 const wxSize& size,
87 long style,
88 const wxString& name)
89{
90 m_clientWindow = (wxMDIClientWindow*) NULL;
91 m_activeChild = (wxMDIChildFrame*) NULL;
92 m_activeMenuBar = (wxMenuBar*) NULL;
93
94 bool success = wxFrame::Create(parent, id, title, pos, size, style, name);
95 if (success)
96 {
97 // TODO: app cannot override OnCreateClient since
98 // wxMDIParentFrame::OnCreateClient will still be called
99 // (we're in the constructor). How to resolve?
100
101 m_clientWindow = OnCreateClient();
102
103 // Uses own style for client style
104 m_clientWindow->CreateClient(this, GetWindowStyleFlag());
105
106 int w, h;
107 GetClientSize(& w, & h);
108 m_clientWindow->SetSize(0, 0, w, h);
109 return TRUE;
110 }
111 else
112 return FALSE;
113}
114
115wxMDIParentFrame::~wxMDIParentFrame()
116{
117 // Make sure we delete the client window last of all
118 RemoveChild(m_clientWindow);
119
120 DestroyChildren();
121
122 delete m_clientWindow;
123 m_clientWindow = NULL;
124}
125
126void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar)
127{
128 m_frameMenuBar = menu_bar;
129
130 SetChildMenuBar((wxMDIChildFrame*) NULL);
131}
132
133void wxMDIParentFrame::OnSize(wxSizeEvent& WXUNUSED(event))
134{
135#if wxUSE_CONSTRAINTS
136 if (GetAutoLayout())
137 Layout();
138#endif
139 int x = 0;
140 int y = 0;
141 int width, height;
142 GetClientSize(&width, &height);
143
144 if ( GetClientWindow() )
145 GetClientWindow()->SetSize(x, y, width, height);
146}
147
148void wxMDIParentFrame::DoGetClientSize(int *width, int *height) const
149{
150 wxFrame::DoGetClientSize(width, height);
151}
152
153void wxMDIParentFrame::OnActivate(wxActivateEvent& WXUNUSED(event))
154{
155 // Do nothing
156}
157
158// Returns the active MDI child window
159wxMDIChildFrame *wxMDIParentFrame::GetActiveChild() const
160{
161 return m_activeChild;
162}
163
164// Create the client window class (don't Create the window,
165// just return a new class)
166wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
167{
168 return new wxMDIClientWindow ;
169}
170
171// Set the child's menu into the parent frame
172void wxMDIParentFrame::SetChildMenuBar(wxMDIChildFrame* child)
173{
174 wxMenuBar* oldMenuBar = m_activeMenuBar;
175
176 if (child == (wxMDIChildFrame*) NULL) // No child: use parent frame
177 {
178 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar))
179 {
180 // if (m_activeMenuBar)
181 // m_activeMenuBar->DestroyMenuBar();
182
183 m_activeMenuBar = GetMenuBar();
184 m_activeMenuBar->CreateMenuBar(this);
185 /*
186 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
187 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
188 */
189 if (oldMenuBar && oldMenuBar->GetMainWidget())
190 XtUnmapWidget((Widget) oldMenuBar->GetMainWidget());
191
192 }
193 }
194 else if (child->GetMenuBar() == (wxMenuBar*) NULL) // No child menu bar: use parent frame
195 {
196 if (GetMenuBar() && (GetMenuBar() != m_activeMenuBar))
197 {
198 // if (m_activeMenuBar)
199 // m_activeMenuBar->DestroyMenuBar();
200 m_activeMenuBar = GetMenuBar();
201 m_activeMenuBar->CreateMenuBar(this);
202 /*
203 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
204 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
205 */
206 if (oldMenuBar && oldMenuBar->GetMainWidget())
207 XtUnmapWidget((Widget) oldMenuBar->GetMainWidget());
208 }
209 }
210 else // The child has a menubar
211 {
212 if (child->GetMenuBar() != m_activeMenuBar)
213 {
214 // if (m_activeMenuBar)
215 // m_activeMenuBar->DestroyMenuBar();
216
217 m_activeMenuBar = child->GetMenuBar();
218 m_activeMenuBar->CreateMenuBar(this);
219 /*
220 if (oldMenuBar && XtIsManaged((Widget) oldMenuBar->GetMainWidget()))
221 XtUnmanageChild((Widget) oldMenuBar->GetMainWidget());
222 */
223 if (oldMenuBar && oldMenuBar->GetMainWidget())
224 XtUnmapWidget((Widget) oldMenuBar->GetMainWidget());
225 }
226 }
227}
228
229// Redirect events to active child first
230bool wxMDIParentFrame::ProcessEvent(wxEvent& event)
231{
232 // Stops the same event being processed repeatedly
233 static wxEventType inEvent = wxEVT_NULL;
234 if (inEvent == event.GetEventType())
235 return FALSE;
236
237 inEvent = event.GetEventType();
238
239 bool res = FALSE;
240 if (m_activeChild && event.IsKindOf(CLASSINFO(wxCommandEvent)))
241 {
242 res = m_activeChild->GetEventHandler()->ProcessEvent(event);
243 }
244
245 if (!res)
246 res = GetEventHandler()->wxEvtHandler::ProcessEvent(event);
247
248 inEvent = wxEVT_NULL;
249
250 return res;
251}
252
253void wxMDIParentFrame::DoSetSize(int x, int y,
254 int width, int height,
255 int sizeFlags)
256{
257 wxWindow::DoSetSize(x, y, width, height, sizeFlags);
258}
259
260void wxMDIParentFrame::DoSetClientSize(int width, int height)
261{
262 wxWindow::DoSetClientSize(width, height);
263}
264
265// Responds to colour changes, and passes event on to children.
266void wxMDIParentFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
267{
268 // TODO
269
270 // Propagate the event to the non-top-level children
271 wxFrame::OnSysColourChanged(event);
272}
273
274// MDI operations
275void wxMDIParentFrame::Cascade()
276{
277 // TODO
278}
279
280void wxMDIParentFrame::Tile()
281{
282 // TODO
283}
284
285void wxMDIParentFrame::ArrangeIcons()
286{
287 // TODO
288}
289
290void wxMDIParentFrame::ActivateNext()
291{
292 // TODO
293}
294
295void wxMDIParentFrame::ActivatePrevious()
296{
297 // TODO
298}
299
300// Default menu selection behaviour - display a help string
301void wxMDIParentFrame::OnMenuHighlight(wxMenuEvent& event)
302{
303 if (GetStatusBar())
304 {
305 if (event.GetMenuId() == -1)
306 SetStatusText("");
307 else
308 {
309 wxMenuBar *menuBar = (wxMenuBar*) NULL;
310 if (GetActiveChild())
311 menuBar = GetActiveChild()->GetMenuBar();
312 else
313 menuBar = GetMenuBar();
314 if (menuBar)
315 {
316 wxString helpString(menuBar->GetHelpString(event.GetMenuId()));
317 if (helpString != "")
318 SetStatusText(helpString);
319 }
320 }
321 }
322}
323
324// Child frame
325
326wxMDIChildFrame::wxMDIChildFrame()
327{
328 m_mdiParentFrame = (wxMDIParentFrame*) NULL;
329}
330
331bool wxMDIChildFrame::Create(wxMDIParentFrame *parent,
332 wxWindowID id,
333 const wxString& title,
334 const wxPoint& pos,
335 const wxSize& size,
336 long style,
337 const wxString& name)
338{
339 SetName(name);
340 SetWindowStyleFlag(style);
341
342 m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE);
343 m_foregroundColour = *wxBLACK;
344 m_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
345
346 if ( id > -1 )
347 m_windowId = id;
348 else
349 m_windowId = (int)NewControlId();
350
351 wxMDIClientWindow* clientWindow = parent->GetClientWindow();
352
353 wxASSERT_MSG( (clientWindow != (wxWindow*) NULL), "Missing MDI client window.");
354
355 if (clientWindow) clientWindow->AddChild(this);
356
357 SetMDIParentFrame(parent);
358
359 int width = size.x;
360 int height = size.y;
361 if (width == -1)
362 width = 200; // TODO: give reasonable default
363 if (height == -1)
364 height = 200; // TODO: give reasonable default
365
366 // We're deactivating the old child
367 wxMDIChildFrame* oldActiveChild = parent->GetActiveChild();
368 if (oldActiveChild)
369 {
370 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, oldActiveChild->GetId());
371 event.SetEventObject( oldActiveChild );
372 oldActiveChild->GetEventHandler()->ProcessEvent(event);
373 }
374
375 // This is the currently active child
376 parent->SetActiveChild((wxMDIChildFrame*) this);
377
378 // This time we'll try a bog-standard bulletin board for
379 // the 'frame'. A main window doesn't seem to work.
380
381 m_mainWidget = (WXWidget) XtVaCreateWidget("client",
382 xmBulletinBoardWidgetClass, (Widget) clientWindow->GetTopWidget(),
383 XmNmarginWidth, 0,
384 XmNmarginHeight, 0,
385 /*
386 XmNrightAttachment, XmATTACH_FORM,
387 XmNleftAttachment, XmATTACH_FORM,
388 XmNtopAttachment, XmATTACH_FORM,
389 XmNbottomAttachment, XmATTACH_FORM,
390 */
391 XmNresizePolicy, XmRESIZE_NONE,
392 NULL);
393
394 XtAddEventHandler((Widget) m_mainWidget, ExposureMask,FALSE,
395 wxUniversalRepaintProc, (XtPointer) this);
396
397 AttachWidget (parent, m_mainWidget, (WXWidget) NULL, pos.x, pos.y, size.x, size.y);
398
399 ChangeBackgroundColour();
400
401 XtManageChild((Widget) m_mainWidget);
402
403 SetTitle(title);
404
405 clientWindow->AddPage(this, title, TRUE);
406 clientWindow->Refresh();
407
408 // Positions the toolbar and status bar -- but we don't have any.
409 // PreResize();
410
411 wxModelessWindows.Append(this);
412 return TRUE;
413}
414
415
416wxMDIChildFrame::~wxMDIChildFrame()
417{
418 if (m_mainWidget)
419 XtRemoveEventHandler((Widget) m_mainWidget, ExposureMask,FALSE,
420 wxUniversalRepaintProc, (XtPointer) this);
421
422 if (GetMDIParentFrame())
423 {
424 wxMDIParentFrame* parentFrame = GetMDIParentFrame();
425
426 if (parentFrame->GetActiveChild() == this)
427 parentFrame->SetActiveChild((wxMDIChildFrame*) NULL);
428 wxMDIClientWindow* clientWindow = parentFrame->GetClientWindow();
429
430 // Remove page if still there
431 {
432 int i = clientWindow->FindPage(this);
433
434 if (i != -1)
435 {
436 clientWindow->RemovePage(i);
437 clientWindow->Refresh();
438 }
439 }
440
441 // Set the selection to the first remaining page
442 if (clientWindow->GetPageCount() > 0)
443 {
444 wxMDIChildFrame* child = (wxMDIChildFrame*) clientWindow->GetPage(0);
445 parentFrame->SetActiveChild(child);
446 parentFrame->SetChildMenuBar(child);
447 }
448 else
449 {
450 parentFrame->SetActiveChild((wxMDIChildFrame*) NULL);
451 parentFrame->SetChildMenuBar((wxMDIChildFrame*) NULL);
452 }
453 }
454}
455
456#if 0
457// Implementation: intercept and act upon raise and lower commands.
458void wxMDIChildFrame::OnRaise()
459{
460 wxMDIParentFrame* parentFrame = (wxMDIParentFrame*) GetParent() ;
461 wxMDIChildFrame* oldActiveChild = parentFrame->GetActiveChild();
462 parentFrame->SetActiveChild(this);
463
464 if (oldActiveChild)
465 {
466 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, oldActiveChild->GetId());
467 event.SetEventObject( oldActiveChild );
468 oldActiveChild->GetEventHandler()->ProcessEvent(event);
469 }
470
471 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, this->GetId());
472 event.SetEventObject( this );
473 this->GetEventHandler()->ProcessEvent(event);
474}
475
476void wxMDIChildFrame::OnLower()
477{
478 wxMDIParentFrame* parentFrame = (wxMDIParentFrame*) GetParent() ;
479 wxMDIChildFrame* oldActiveChild = parentFrame->GetActiveChild();
480
481 if (oldActiveChild == this)
482 {
483 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, oldActiveChild->GetId());
484 event.SetEventObject( oldActiveChild );
485 oldActiveChild->GetEventHandler()->ProcessEvent(event);
486 }
487 // TODO: unfortunately we don't now know which is the top-most child,
488 // so make the active child NULL.
489 parentFrame->SetActiveChild((wxMDIChildFrame*) NULL);
490}
491#endif
492
493// Set the client size (i.e. leave the calculation of borders etc.
494// to wxWidgets)
495void wxMDIChildFrame::DoSetClientSize(int width, int height)
496{
497 wxWindow::DoSetClientSize(width, height);
498}
499
500void wxMDIChildFrame::DoGetClientSize(int* width, int* height) const
501{
502 wxWindow::DoGetSize(width, height);
503}
504
505void wxMDIChildFrame::DoSetSize(int x, int y, int width, int height, int sizeFlags)
506{
507 wxWindow::DoSetSize(x, y, width, height, sizeFlags);
508}
509
510void wxMDIChildFrame::DoGetSize(int* width, int* height) const
511{
512 wxWindow::DoGetSize(width, height);
513}
514
515void wxMDIChildFrame::DoGetPosition(int *x, int *y) const
516{
517 wxWindow::DoGetPosition(x, y);
518}
519
520bool wxMDIChildFrame::Show(bool show)
521{
522 SetVisibleStatus( show );
523 return wxWindow::Show(show);
524}
525
526void wxMDIChildFrame::SetMenuBar(wxMenuBar *menuBar)
527{
528 // Don't create the underlying menubar yet; need to recreate
529 // it every time the child is activated.
530 m_frameMenuBar = menuBar;
531
532 // We make the assumption that if you're setting the menubar,
533 // this is the currently active child.
534 GetMDIParentFrame()->SetChildMenuBar(this);
535}
536
537// Set icon
538void wxMDIChildFrame::SetIcon(const wxIcon& icon)
539{
540 m_icons = wxIconBundle( icon );
541
542 if (icon.Ok())
543 {
544 // Not appropriate since there are no icons in
545 // a tabbed window
546 }
547}
548
549void wxMDIChildFrame::SetIcons(const wxIconBundle& icons)
550{
551 m_icons = icons;
552}
553
554void wxMDIChildFrame::SetTitle(const wxString& title)
555{
556 wxTopLevelWindow::SetTitle( title );
557 wxMDIClientWindow* clientWindow = GetMDIParentFrame()->GetClientWindow();
558
559 // Remove page if still there
560 {
561 int i = clientWindow->FindPage(this);
562
563 if (i != -1)
564 clientWindow->SetPageText(i, title);
565 }
566}
567
568// MDI operations
569void wxMDIChildFrame::Maximize()
570{
571 // TODO
572}
573
574void wxMDIChildFrame::Iconize(bool WXUNUSED(iconize))
575{
576 // TODO
577}
578
579bool wxMDIChildFrame::IsIconized() const
580{
581 return FALSE;
582}
583
584// Is it maximized? Always maximized under Motif, using the
585// tabbed MDI implementation.
586bool wxMDIChildFrame::IsMaximized(void) const
587{
588 return TRUE;
589}
590
591void wxMDIChildFrame::Restore()
592{
593 // TODO
594}
595
596void wxMDIChildFrame::Activate()
597{
598 // TODO
599}
600
601void wxMDIChildFrame::CaptureMouse()
602{
603 wxWindow::CaptureMouse();
604}
605
606void wxMDIChildFrame::ReleaseMouse()
607{
608 wxWindow::ReleaseMouse();
609}
610
611void wxMDIChildFrame::Raise()
612{
613 wxWindow::Raise();
614}
615
616void wxMDIChildFrame::Lower(void)
617{
618 wxWindow::Raise();
619}
620
621void wxMDIChildFrame::SetSizeHints(int WXUNUSED(minW), int WXUNUSED(minH), int WXUNUSED(maxW), int WXUNUSED(maxH), int WXUNUSED(incW), int WXUNUSED(incH))
622{
623}
624
625// Client window
626
627wxMDIClientWindow::wxMDIClientWindow()
628{
629}
630
631wxMDIClientWindow::~wxMDIClientWindow()
632{
633 // By the time this destructor is called, the child frames will have been
634 // deleted and removed from the notebook/client window.
635 DestroyChildren();
636
637 m_mainWidget = (WXWidget) 0;
638}
639
640bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style)
641{
642 SetWindowStyleFlag(style);
643
644 // m_windowParent = parent;
645 // m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_APPWORKSPACE);
646
647 bool success = wxNotebook::Create(parent, wxID_NOTEBOOK_CLIENT_AREA, wxPoint(0, 0), wxSize(100, 100), 0);
648 if (success)
649 {
650 wxFont font(10, wxSWISS, wxNORMAL, wxNORMAL);
651 SetFont(font);
652 return TRUE;
653 }
654 else
655 return FALSE;
656}
657
658int wxMDIClientWindow::FindPage(const wxNotebookPage* page)
659{
660 for (int i = GetPageCount() - 1; i >= 0; --i)
661 {
662 if (GetPage(i) == page)
663 return i;
664 }
665
666 return -1;
667}
668
669void wxMDIClientWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags)
670{
671 wxWindow::DoSetSize(x, y, width, height, sizeFlags);
672}
673
674void wxMDIClientWindow::DoSetClientSize(int width, int height)
675{
676 wxWindow::DoSetClientSize(width, height);
677}
678
679void wxMDIClientWindow::DoGetClientSize(int *width, int *height) const
680{
681 wxWindow::DoGetClientSize(width, height);
682}
683
684void wxMDIClientWindow::DoGetSize(int *width, int *height) const
685{
686 wxWindow::DoGetSize(width, height);
687}
688
689void wxMDIClientWindow::DoGetPosition(int *x, int *y) const
690{
691 wxWindow::DoGetPosition(x, y);
692}
693
694void wxMDIClientWindow::OnScroll(wxScrollEvent& event)
695{
696 // Default(); // Default processing: OBSOLETE FUNCTION
697 event.Skip();
698}
699
700void wxMDIClientWindow::OnPageChanged(wxNotebookEvent& event)
701{
702 // Notify child that it has been activated
703 if (event.GetOldSelection() != -1)
704 {
705 wxMDIChildFrame* oldChild = (wxMDIChildFrame*) GetPage(event.GetOldSelection());
706 if (oldChild)
707 {
708 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, oldChild->GetId());
709 event.SetEventObject( oldChild );
710 oldChild->GetEventHandler()->ProcessEvent(event);
711 }
712 }
713 if (event.GetSelection() != -1)
714 {
715 wxMDIChildFrame* activeChild = (wxMDIChildFrame*) GetPage(event.GetSelection());
716 if (activeChild)
717 {
718 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, activeChild->GetId());
719 event.SetEventObject( activeChild );
720 activeChild->GetEventHandler()->ProcessEvent(event);
721
722 if (activeChild->GetMDIParentFrame())
723 {
724 activeChild->GetMDIParentFrame()->SetActiveChild(activeChild);
725 activeChild->GetMDIParentFrame()->SetChildMenuBar(activeChild);
726 }
727 }
728 }
729 event.Skip();
730}