]> git.saurik.com Git - wxWidgets.git/blob - src/motif/mdi.cpp
01baaecd93e4b6272394ef81b8b917d9500ee04c
[wxWidgets.git] / src / motif / mdi.cpp
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
48 extern wxList wxModelessWindows;
49
50 // Implemented in frame.cpp
51 extern void wxFrameFocusProc(Widget workArea, XtPointer clientData,
52 XmAnyCallbackStruct *cbs);
53
54 #define wxID_NOTEBOOK_CLIENT_AREA wxID_HIGHEST + 100
55
56 IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame)
57 IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame)
58 IMPLEMENT_DYNAMIC_CLASS(wxMDIClientWindow, wxNotebook)
59
60 BEGIN_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)
65 END_EVENT_TABLE()
66
67 BEGIN_EVENT_TABLE(wxMDIClientWindow, wxNotebook)
68 EVT_SCROLL(wxMDIClientWindow::OnScroll)
69 EVT_NOTEBOOK_PAGE_CHANGED(wxID_NOTEBOOK_CLIENT_AREA, wxMDIClientWindow::OnPageChanged)
70 END_EVENT_TABLE()
71
72
73 // Parent frame
74
75 wxMDIParentFrame::wxMDIParentFrame()
76 {
77 m_clientWindow = (wxMDIClientWindow*) NULL;
78 m_activeChild = (wxMDIChildFrame*) NULL;
79 m_activeMenuBar = (wxMenuBar*) NULL;
80 }
81
82 bool 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
115 wxMDIParentFrame::~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
126 void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar)
127 {
128 m_frameMenuBar = menu_bar;
129
130 SetChildMenuBar((wxMDIChildFrame*) NULL);
131 }
132
133 void 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
148 void wxMDIParentFrame::DoGetClientSize(int *width, int *height) const
149 {
150 wxFrame::DoGetClientSize(width, height);
151 }
152
153 void wxMDIParentFrame::OnActivate(wxActivateEvent& WXUNUSED(event))
154 {
155 // Do nothing
156 }
157
158 // Returns the active MDI child window
159 wxMDIChildFrame *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)
166 wxMDIClientWindow *wxMDIParentFrame::OnCreateClient()
167 {
168 return new wxMDIClientWindow ;
169 }
170
171 // Set the child's menu into the parent frame
172 void 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
230 bool 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
253 void 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
260 void 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.
266 void 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
275 void wxMDIParentFrame::Cascade()
276 {
277 // TODO
278 }
279
280 void wxMDIParentFrame::Tile(wxOrientation WXUNUSED(orient))
281 {
282 // TODO
283 }
284
285 void wxMDIParentFrame::ArrangeIcons()
286 {
287 // TODO
288 }
289
290 void wxMDIParentFrame::ActivateNext()
291 {
292 // TODO
293 }
294
295 void wxMDIParentFrame::ActivatePrevious()
296 {
297 // TODO
298 }
299
300 // Default menu selection behaviour - display a help string
301 void 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
326 wxMDIChildFrame::wxMDIChildFrame()
327 {
328 m_mdiParentFrame = (wxMDIParentFrame*) NULL;
329 }
330
331 bool 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
416 wxMDIChildFrame::~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.
458 void 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
476 void 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)
495 void wxMDIChildFrame::DoSetClientSize(int width, int height)
496 {
497 wxWindow::DoSetClientSize(width, height);
498 }
499
500 void wxMDIChildFrame::DoGetClientSize(int* width, int* height) const
501 {
502 wxWindow::DoGetSize(width, height);
503 }
504
505 void wxMDIChildFrame::DoSetSize(int x, int y, int width, int height, int sizeFlags)
506 {
507 wxWindow::DoSetSize(x, y, width, height, sizeFlags);
508 }
509
510 void wxMDIChildFrame::DoGetSize(int* width, int* height) const
511 {
512 wxWindow::DoGetSize(width, height);
513 }
514
515 void wxMDIChildFrame::DoGetPosition(int *x, int *y) const
516 {
517 wxWindow::DoGetPosition(x, y);
518 }
519
520 bool wxMDIChildFrame::Show(bool show)
521 {
522 SetVisibleStatus( show );
523 return wxWindow::Show(show);
524 }
525
526 void 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
538 void 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
549 void wxMDIChildFrame::SetIcons(const wxIconBundle& icons)
550 {
551 m_icons = icons;
552 }
553
554 void 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
569 void wxMDIChildFrame::Maximize()
570 {
571 // TODO
572 }
573
574 void wxMDIChildFrame::Iconize(bool WXUNUSED(iconize))
575 {
576 // TODO
577 }
578
579 bool wxMDIChildFrame::IsIconized() const
580 {
581 return false;
582 }
583
584 // Is it maximized? Always maximized under Motif, using the
585 // tabbed MDI implementation.
586 bool wxMDIChildFrame::IsMaximized(void) const
587 {
588 return true;
589 }
590
591 void wxMDIChildFrame::Restore()
592 {
593 // TODO
594 }
595
596 void wxMDIChildFrame::Activate()
597 {
598 // TODO
599 }
600
601 void wxMDIChildFrame::CaptureMouse()
602 {
603 wxWindow::CaptureMouse();
604 }
605
606 void wxMDIChildFrame::ReleaseMouse()
607 {
608 wxWindow::ReleaseMouse();
609 }
610
611 void wxMDIChildFrame::Raise()
612 {
613 wxWindow::Raise();
614 }
615
616 void wxMDIChildFrame::Lower(void)
617 {
618 wxWindow::Raise();
619 }
620
621 void wxMDIChildFrame::DoSetSizeHints(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
627 wxMDIClientWindow::wxMDIClientWindow()
628 {
629 }
630
631 wxMDIClientWindow::~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
640 bool 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
658 int 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
669 void wxMDIClientWindow::DoSetSize(int x, int y, int width, int height, int sizeFlags)
670 {
671 wxWindow::DoSetSize(x, y, width, height, sizeFlags);
672 }
673
674 void wxMDIClientWindow::DoSetClientSize(int width, int height)
675 {
676 wxWindow::DoSetClientSize(width, height);
677 }
678
679 void wxMDIClientWindow::DoGetClientSize(int *width, int *height) const
680 {
681 wxWindow::DoGetClientSize(width, height);
682 }
683
684 void wxMDIClientWindow::DoGetSize(int *width, int *height) const
685 {
686 wxWindow::DoGetSize(width, height);
687 }
688
689 void wxMDIClientWindow::DoGetPosition(int *x, int *y) const
690 {
691 wxWindow::DoGetPosition(x, y);
692 }
693
694 void wxMDIClientWindow::OnScroll(wxScrollEvent& event)
695 {
696 // Default(); // Default processing: OBSOLETE FUNCTION
697 event.Skip();
698 }
699
700 void 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 }