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