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