Committing in .
[wxWidgets.git] / src / motif / frame.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: frame.cpp
3 // Purpose: wxFrame
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 "frame.h"
14 #endif
15
16 #include "wx/frame.h"
17 #include "wx/statusbr.h"
18 #include "wx/toolbar.h"
19 #include "wx/menuitem.h"
20 #include "wx/menu.h"
21 #include "wx/dcclient.h"
22 #include "wx/dialog.h"
23 #include "wx/settings.h"
24 #include "wx/app.h"
25 #include "wx/utils.h"
26
27 #ifdef __VMS__
28 #pragma message disable nosimpint
29 #endif
30 #if defined(__ultrix) || defined(__sgi)
31 #include <Xm/Frame.h>
32 #endif
33
34 #include <Xm/Xm.h>
35 #include <X11/Shell.h>
36 #if XmVersion >= 1002
37 #include <Xm/XmAll.h>
38 #else
39 #include <Xm/Frame.h>
40 #endif
41 #include <Xm/MwmUtil.h>
42 #include <Xm/BulletinB.h>
43 #include <Xm/Form.h>
44 #include <Xm/MainW.h>
45 #include <Xm/RowColumn.h>
46 #include <Xm/Label.h>
47 #include <Xm/AtomMgr.h>
48 #include <Xm/LabelG.h>
49 #include <Xm/Frame.h>
50 #if XmVersion > 1000
51 #include <Xm/Protocols.h>
52 #endif
53 #ifdef __VMS__
54 #pragma message enable nosimpint
55 #endif
56
57 #include "wx/motif/private.h"
58
59 void wxCloseFrameCallback(Widget, XtPointer, XmAnyCallbackStruct *cbs);
60 void wxFrameFocusProc(Widget workArea, XtPointer clientData,
61 XmAnyCallbackStruct *cbs);
62 static void wxFrameMapProc(Widget frameShell, XtPointer clientData,
63 XCrossingEvent * event);
64
65 extern wxList wxModelessWindows;
66 extern wxList wxPendingDelete;
67
68 // TODO: this should be tidied so that any frame can be the
69 // top frame
70 static bool wxTopLevelUsed = FALSE;
71
72 #if !USE_SHARED_LIBRARY
73 BEGIN_EVENT_TABLE(wxFrame, wxWindow)
74 EVT_SIZE(wxFrame::OnSize)
75 EVT_ACTIVATE(wxFrame::OnActivate)
76 EVT_MENU_HIGHLIGHT_ALL(wxFrame::OnMenuHighlight)
77 EVT_SYS_COLOUR_CHANGED(wxFrame::OnSysColourChanged)
78 EVT_IDLE(wxFrame::OnIdle)
79 EVT_CLOSE(wxFrame::OnCloseWindow)
80 END_EVENT_TABLE()
81
82 IMPLEMENT_DYNAMIC_CLASS(wxFrame, wxWindow)
83 #endif
84
85 #if wxUSE_NATIVE_STATUSBAR
86 bool wxFrame::m_useNativeStatusBar = TRUE;
87 #else
88 bool wxFrame::m_useNativeStatusBar = FALSE;
89 #endif
90
91 wxFrame::wxFrame()
92 {
93 #if wxUSE_TOOLBAR
94 m_frameToolBar = NULL ;
95 #endif // wxUSE_TOOLBAR
96
97 m_frameMenuBar = NULL;
98 m_frameStatusBar = NULL;
99
100 m_parent = NULL;
101 m_iconized = FALSE;
102
103 //// Motif-specific
104 m_frameShell = (WXWidget) NULL;
105 m_frameWidget = (WXWidget) NULL;;
106 m_workArea = (WXWidget) NULL;;
107 m_clientArea = (WXWidget) NULL;;
108 m_visibleStatus = TRUE;
109 m_title = "";
110 }
111
112 bool wxFrame::Create(wxWindow *parent,
113 wxWindowID id,
114 const wxString& title,
115 const wxPoint& pos,
116 const wxSize& size,
117 long style,
118 const wxString& name)
119 {
120 if (!parent)
121 wxTopLevelWindows.Append(this);
122
123 SetName(name);
124
125 m_windowStyle = style;
126 m_frameMenuBar = NULL;
127 #if wxUSE_TOOLBAR
128 m_frameToolBar = NULL ;
129 #endif // wxUSE_TOOLBAR
130 m_frameStatusBar = NULL;
131
132 //// Motif-specific
133 m_frameShell = (WXWidget) NULL;
134 m_frameWidget = (WXWidget) NULL;;
135 m_workArea = (WXWidget) NULL;;
136 m_clientArea = (WXWidget) NULL;;
137 m_visibleStatus = TRUE;
138 m_title = "";
139
140 m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE);
141 m_foregroundColour = *wxBLACK;
142 m_font = wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT);
143
144 if ( id > -1 )
145 m_windowId = id;
146 else
147 m_windowId = (int)NewControlId();
148
149 if (parent) parent->AddChild(this);
150
151 wxModelessWindows.Append(this);
152
153 int x = pos.x, y = pos.y;
154 int width = size.x, height = size.y;
155
156 // Set reasonable values for position and size if defaults have been
157 // requested
158 //
159 // MB TODO: something better than these arbitrary values ?
160 // VZ should use X resources for this...
161 if ( width == -1 )
162 width = 400;
163 if ( height == -1 )
164 height = 400;
165
166 int displayW, displayH;
167 wxDisplaySize( &displayW, &displayH );
168
169 if ( x == -1 )
170 {
171 x = (displayW - width) / 2;
172 if (x < 10) x = 10;
173 }
174 if ( y == -1 )
175 {
176 y = (displayH - height) / 2;
177 if (y < 10) y = 10;
178 }
179
180 if (wxTopLevelUsed)
181 {
182 // Change suggested by Matthew Flatt
183 m_frameShell = (WXWidget)XtAppCreateShell
184 (
185 name,
186 wxTheApp->GetClassName(),
187 topLevelShellWidgetClass,
188 (Display*) wxGetDisplay(),
189 NULL,
190 0
191 );
192 }
193 else
194 {
195 m_frameShell = wxTheApp->GetTopLevelWidget();
196 wxTopLevelUsed = TRUE;
197 }
198
199 XtVaSetValues((Widget) m_frameShell,
200 // Allows menu to resize
201 XmNallowShellResize, True,
202 XmNdeleteResponse, XmDO_NOTHING,
203 XmNmappedWhenManaged, False,
204 XmNiconic, (style & wxICONIZE) ? TRUE : FALSE,
205 NULL);
206
207 if (!title.IsNull())
208 XtVaSetValues((Widget) m_frameShell,
209 XmNtitle, (const char*) title,
210 NULL);
211
212 m_frameWidget = (WXWidget) XtVaCreateManagedWidget("main_window",
213 xmMainWindowWidgetClass, (Widget) m_frameShell,
214 XmNresizePolicy, XmRESIZE_NONE,
215 NULL);
216
217 m_workArea = (WXWidget) XtVaCreateWidget("form",
218 xmFormWidgetClass, (Widget) m_frameWidget,
219 XmNresizePolicy, XmRESIZE_NONE,
220 NULL);
221
222 m_clientArea = (WXWidget) XtVaCreateWidget("client",
223 xmBulletinBoardWidgetClass, (Widget) m_workArea,
224 XmNmarginWidth, 0,
225 XmNmarginHeight, 0,
226 XmNrightAttachment, XmATTACH_FORM,
227 XmNleftAttachment, XmATTACH_FORM,
228 XmNtopAttachment, XmATTACH_FORM,
229 XmNbottomAttachment, XmATTACH_FORM,
230 // XmNresizePolicy, XmRESIZE_ANY,
231 NULL);
232
233 wxLogDebug("Created frame (0x%08x) with work area 0x%08x and client "
234 "area 0x%08x", m_frameWidget, m_workArea, m_clientArea);
235
236 XtAddEventHandler((Widget) m_clientArea, ExposureMask,FALSE,
237 wxUniversalRepaintProc, (XtPointer) this);
238
239 XtVaSetValues((Widget) m_frameWidget,
240 XmNworkWindow, (Widget) m_workArea,
241 NULL);
242
243 XtManageChild((Widget) m_clientArea);
244 XtManageChild((Widget) m_workArea);
245
246 wxAddWindowToTable((Widget) m_workArea, this);
247
248 XtTranslations ptr ;
249
250 XtOverrideTranslations((Widget) m_workArea,
251 ptr = XtParseTranslationTable("<Configure>: resize()"));
252
253 XtFree((char *)ptr);
254
255 XtAddCallback((Widget) m_workArea, XmNfocusCallback,
256 (XtCallbackProc)wxFrameFocusProc, (XtPointer)this);
257
258 /* Part of show-&-hide fix */
259 XtAddEventHandler((Widget) m_frameShell, StructureNotifyMask,
260 False, (XtEventHandler)wxFrameMapProc,
261 (XtPointer)m_workArea);
262
263 if (x > -1)
264 XtVaSetValues((Widget) m_frameShell, XmNx, x, NULL);
265 if (y > -1)
266 XtVaSetValues((Widget) m_frameShell, XmNy, y, NULL);
267 if (width > -1)
268 XtVaSetValues((Widget) m_frameShell, XmNwidth, width, NULL);
269 if (height > -1)
270 XtVaSetValues((Widget) m_frameShell, XmNheight, height, NULL);
271
272 m_mainWidget = m_frameWidget;
273
274 ChangeFont(FALSE);
275
276 // This patch comes from Torsten Liermann lier@lier1.muc.de
277 if (XmIsMotifWMRunning( (Widget) m_frameShell ))
278 {
279 int decor = 0 ;
280 if (style & wxRESIZE_BORDER)
281 decor |= MWM_DECOR_RESIZEH ;
282 if (style & wxSYSTEM_MENU)
283 decor |= MWM_DECOR_MENU;
284 if ((style & wxCAPTION) ||
285 (style & wxTINY_CAPTION_HORIZ) ||
286 (style & wxTINY_CAPTION_VERT))
287 decor |= MWM_DECOR_TITLE;
288 if (style & wxTHICK_FRAME)
289 decor |= MWM_DECOR_BORDER;
290 if (style & wxTHICK_FRAME)
291 decor |= MWM_DECOR_BORDER;
292 if (style & wxMINIMIZE_BOX)
293 decor |= MWM_DECOR_MINIMIZE;
294 if (style & wxMAXIMIZE_BOX)
295 decor |= MWM_DECOR_MAXIMIZE;
296 XtVaSetValues((Widget) m_frameShell,XmNmwmDecorations,decor,NULL) ;
297 }
298 // This allows non-Motif window managers to support at least the
299 // no-decorations case.
300 else
301 {
302 if (style == 0)
303 XtVaSetValues((Widget) m_frameShell,XmNoverrideRedirect,TRUE,NULL);
304 }
305 XtRealizeWidget((Widget) m_frameShell);
306
307 // Intercept CLOSE messages from the window manager
308 Atom WM_DELETE_WINDOW = XmInternAtom(XtDisplay((Widget) m_frameShell), "WM_DELETE_WINDOW", False);
309 #if (XmREVISION > 1 || XmVERSION > 1)
310 XmAddWMProtocolCallback((Widget) m_frameShell, WM_DELETE_WINDOW, (XtCallbackProc) wxCloseFrameCallback, (XtPointer)this);
311 #else
312 #if XmREVISION == 1
313 XmAddWMProtocolCallback((Widget) m_frameShell, WM_DELETE_WINDOW, (XtCallbackProc) wxCloseFrameCallback, (caddr_t)this);
314 #else
315 XmAddWMProtocolCallback((Widget) m_frameShell, WM_DELETE_WINDOW, (void (*)())wxCloseFrameCallback, (caddr_t)this);
316 #endif
317 #endif
318
319 ChangeBackgroundColour();
320
321 PreResize();
322
323 wxSizeEvent sizeEvent(wxSize(width, height), GetId());
324 sizeEvent.SetEventObject(this);
325
326 GetEventHandler()->ProcessEvent(sizeEvent);
327
328 return TRUE;
329 }
330
331 wxFrame::~wxFrame()
332 {
333 m_isBeingDeleted = TRUE;
334
335 if (m_clientArea)
336 XtRemoveEventHandler((Widget) m_clientArea, ExposureMask, FALSE,
337 wxUniversalRepaintProc, (XtPointer) this);
338
339 if (GetMainWidget())
340 Show(FALSE);
341
342 if (m_frameMenuBar)
343 {
344 m_frameMenuBar->DestroyMenuBar();
345
346 // Hack to stop core dump on Ultrix, OSF, for some strange reason.
347 #if MOTIF_MENUBAR_DELETE_FIX
348 GetMenuBar()->SetMainWidget((WXWidget) NULL);
349 #endif
350 delete m_frameMenuBar;
351 m_frameMenuBar = NULL;
352 }
353
354 wxTopLevelWindows.DeleteObject(this);
355 wxModelessWindows.DeleteObject(this);
356
357 if (m_frameStatusBar)
358 delete m_frameStatusBar;
359
360 DestroyChildren();
361
362 /*
363 int i;
364 for (i = 0; i < wxMAX_STATUS; i++)
365 if (statusTextWidget[i])
366 XtDestroyWidget (statusTextWidget[i]);
367
368 if (statusLineForm)
369 XtDestroyWidget (statusLineForm);
370
371 if (statusLineWidget)
372 XtDestroyWidget (statusLineWidget);
373 */
374
375 if (m_workArea)
376 {
377 wxDeleteWindowFromTable((Widget) m_workArea);
378
379 XtDestroyWidget ((Widget) m_workArea);
380 }
381
382 if (m_frameWidget)
383 {
384 wxDeleteWindowFromTable((Widget) m_frameWidget);
385 XtDestroyWidget ((Widget) m_frameWidget);
386 }
387
388 if (m_frameShell)
389 XtDestroyWidget ((Widget) m_frameShell);
390
391 SetMainWidget((WXWidget) NULL);
392
393 /* Check if it's the last top-level window */
394
395 if (wxTheApp && (wxTopLevelWindows.Number() == 0))
396 {
397 wxTheApp->SetTopWindow(NULL);
398
399 if (wxTheApp->GetExitOnFrameDelete())
400 {
401 // Signal to the app that we're going to close
402 wxTheApp->ExitMainLoop();
403 }
404 }
405
406 }
407
408 // Get size *available for subwindows* i.e. excluding menu bar, toolbar etc.
409 void wxFrame::DoGetClientSize(int *x, int *y) const
410 {
411 Dimension xx, yy;
412 XtVaGetValues((Widget) m_workArea, XmNwidth, &xx, XmNheight, &yy, NULL);
413
414 if (m_frameStatusBar)
415 {
416 int sbw, sbh;
417 m_frameStatusBar->GetSize(& sbw, & sbh);
418 yy -= sbh;
419 }
420 #if wxUSE_TOOLBAR
421 if (m_frameToolBar)
422 {
423 int tbw, tbh;
424 m_frameToolBar->GetSize(& tbw, & tbh);
425 if (m_frameToolBar->GetWindowStyleFlag() & wxTB_VERTICAL)
426 xx -= tbw;
427 else
428 yy -= tbh;
429 }
430 #endif // wxUSE_TOOLBAR
431 /*
432 if (GetMenuBar() != (wxMenuBar*) NULL)
433 {
434 // it seems that if a frame holds a panel, the menu bar size
435 // gets automatically taken care of --- grano@cs.helsinki.fi 4.4.95
436 bool hasSubPanel = FALSE;
437 for(wxNode* node = GetChildren().First(); node; node = node->Next())
438 {
439 wxWindow *win = (wxWindow *)node->Data();
440 hasSubPanel = (win->IsKindOf(CLASSINFO(wxPanel)) && !win->IsKindOf(CLASSINFO(wxDialog)));
441
442 if (hasSubPanel)
443 break;
444 }
445 if (! hasSubPanel) {
446 Dimension ys;
447 XtVaGetValues((Widget) GetMenuBarWidget(), XmNheight, &ys, NULL);
448 yy -= ys;
449 }
450 }
451 */
452
453 *x = xx; *y = yy;
454 }
455
456 // Set the client size (i.e. leave the calculation of borders etc.
457 // to wxWindows)
458 void wxFrame::DoSetClientSize(int width, int height)
459 {
460 // Calculate how large the new main window should be
461 // by finding the difference between the client area and the
462 // main window area, and adding on to the new client area
463 if (width > -1)
464 XtVaSetValues((Widget) m_workArea, XmNwidth, width, NULL);
465
466 if (height > -1)
467 {
468 if (m_frameStatusBar)
469 {
470 int sbw, sbh;
471 m_frameStatusBar->GetSize(& sbw, & sbh);
472 height += sbh;
473 }
474 #if wxUSE_TOOLBAR
475 if (m_frameToolBar)
476 {
477 int tbw, tbh;
478 m_frameToolBar->GetSize(& tbw, & tbh);
479 if (m_frameToolBar->GetWindowStyleFlag() & wxTB_VERTICAL)
480 width += tbw;
481 else
482 height += tbh;
483 }
484 #endif // wxUSE_TOOLBAR
485
486 XtVaSetValues((Widget) m_workArea, XmNheight, height, NULL);
487 }
488 PreResize();
489
490 wxSizeEvent sizeEvent(wxSize(width, height), GetId());
491 sizeEvent.SetEventObject(this);
492
493 GetEventHandler()->ProcessEvent(sizeEvent);
494
495 }
496
497 void wxFrame::DoGetSize(int *width, int *height) const
498 {
499 Dimension xx, yy;
500 XtVaGetValues((Widget) m_frameShell, XmNwidth, &xx, XmNheight, &yy, NULL);
501 *width = xx; *height = yy;
502 }
503
504 void wxFrame::DoGetPosition(int *x, int *y) const
505 {
506 Window parent_window = XtWindow((Widget) m_frameShell),
507 next_parent = XtWindow((Widget) m_frameShell),
508 root = RootWindowOfScreen(XtScreen((Widget) m_frameShell));
509
510 // search for the parent that is child of ROOT, because the WM may
511 // reparent twice and notify only the next parent (like FVWM)
512 while (next_parent != root) {
513 Window *theChildren; unsigned int n;
514 parent_window = next_parent;
515 XQueryTree(XtDisplay((Widget) m_frameShell), parent_window, &root,
516 &next_parent, &theChildren, &n);
517 XFree(theChildren); // not needed
518 }
519 int xx, yy; unsigned int dummy;
520 XGetGeometry(XtDisplay((Widget) m_frameShell), parent_window, &root,
521 &xx, &yy, &dummy, &dummy, &dummy, &dummy);
522 if (x) *x = xx;
523 if (y) *y = yy;
524 }
525
526 void wxFrame::DoSetSize(int x, int y, int width, int height, int WXUNUSED(sizeFlags))
527 {
528 if (x > -1)
529 XtVaSetValues((Widget) m_frameShell, XmNx, x, NULL);
530 if (y > -1)
531 XtVaSetValues((Widget) m_frameShell, XmNy, y, NULL);
532 if (width > -1)
533 XtVaSetValues((Widget) m_frameWidget, XmNwidth, width, NULL);
534 if (height > -1)
535 XtVaSetValues((Widget) m_frameWidget, XmNheight, height, NULL);
536
537 if (!(height == -1 && width == -1))
538 {
539 PreResize();
540
541 wxSizeEvent sizeEvent(wxSize(width, height), GetId());
542 sizeEvent.SetEventObject(this);
543
544 GetEventHandler()->ProcessEvent(sizeEvent);
545 }
546 }
547
548 bool wxFrame::Show(bool show)
549 {
550 if (!m_frameShell)
551 return wxWindow::Show(show);
552
553 m_visibleStatus = show; /* show-&-hide fix */
554
555 m_isShown = show;
556 if (show) {
557 XtMapWidget((Widget) m_frameShell);
558 XRaiseWindow(XtDisplay((Widget) m_frameShell), XtWindow((Widget) m_frameShell));
559 } else {
560 XtUnmapWidget((Widget) m_frameShell);
561 // XmUpdateDisplay(wxTheApp->topLevel); // Experimental: may be responsible for crashes
562 }
563 return TRUE;
564 }
565
566 void wxFrame::Iconize(bool iconize)
567 {
568 if (!iconize)
569 Show(TRUE);
570
571 if (m_frameShell)
572 XtVaSetValues((Widget) m_frameShell, XmNiconic, (Boolean)iconize, NULL);
573 }
574
575 // Equivalent to maximize/restore in Windows
576 void wxFrame::Maximize(bool maximize)
577 {
578 Show(TRUE);
579
580 if (maximize && m_frameShell)
581 XtVaSetValues((Widget) m_frameShell, XmNiconic, FALSE, NULL);
582 }
583
584 bool wxFrame::IsIconized() const
585 {
586 if (!m_frameShell)
587 return FALSE;
588
589 Boolean iconic;
590 XtVaGetValues((Widget) m_frameShell, XmNiconic, &iconic, NULL);
591 return iconic;
592 }
593
594 // Is it maximized?
595 bool wxFrame::IsMaximized(void) const
596 {
597 // No maximizing in Motif (?)
598 return FALSE;
599 }
600
601 void wxFrame::SetTitle(const wxString& title)
602 {
603 if (title == m_title)
604 return;
605
606 m_title = title;
607
608 if (!title.IsNull())
609 XtVaSetValues((Widget) m_frameShell,
610 XmNtitle, (const char*) title,
611 XmNiconName, (const char*) title,
612 NULL);
613 }
614
615 void wxFrame::SetIcon(const wxIcon& icon)
616 {
617 m_icon = icon;
618
619 if (!m_frameShell)
620 return;
621
622 if (!icon.Ok() || !icon.GetPixmap())
623 return;
624
625 XtVaSetValues((Widget) m_frameShell, XtNiconPixmap, icon.GetPixmap(), NULL);
626 }
627
628 wxStatusBar *wxFrame::OnCreateStatusBar(int number, long style, wxWindowID id,
629 const wxString& name)
630 {
631 wxStatusBar *statusBar = NULL;
632
633 statusBar = new wxStatusBar(this, id, wxPoint(0, 0), wxSize(100, 20),
634 style, name);
635
636 // Set the height according to the font and the border size
637 wxClientDC dc(statusBar);
638 dc.SetFont(statusBar->GetFont());
639
640 long x, y;
641 dc.GetTextExtent("X", &x, &y);
642
643 int height = (int)( (y * 1.1) + 2* statusBar->GetBorderY());
644
645 statusBar->SetSize(-1, -1, 100, height);
646
647 statusBar->SetFieldsCount(number);
648 return statusBar;
649 }
650
651 wxStatusBar* wxFrame::CreateStatusBar(int number, long style, wxWindowID id,
652 const wxString& name)
653 {
654 // Calling CreateStatusBar twice is an error.
655 wxCHECK_MSG( m_frameStatusBar == NULL, FALSE,
656 "recreating status bar in wxFrame" );
657
658 m_frameStatusBar = OnCreateStatusBar(number, style, id,
659 name);
660 if ( m_frameStatusBar )
661 {
662 PositionStatusBar();
663 return m_frameStatusBar;
664 }
665 else
666 return NULL;
667 }
668
669 void wxFrame::SetStatusText(const wxString& text, int number)
670 {
671 wxCHECK_RET( m_frameStatusBar != NULL, "no statusbar to set text for" );
672
673 m_frameStatusBar->SetStatusText(text, number);
674 }
675
676 void wxFrame::SetStatusWidths(int n, const int widths_field[])
677 {
678 wxCHECK_RET( m_frameStatusBar != NULL, "no statusbar to set widths for" );
679
680 m_frameStatusBar->SetStatusWidths(n, widths_field);
681 PositionStatusBar();
682 }
683
684 void wxFrame::PositionStatusBar()
685 {
686 if (!m_frameStatusBar)
687 return;
688
689 int w, h;
690 GetClientSize(&w, &h);
691 int sw, sh;
692 m_frameStatusBar->GetSize(&sw, &sh);
693
694 // Since we wish the status bar to be directly under the client area,
695 // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS.
696 m_frameStatusBar->SetSize(0, h, w, sh);
697 }
698
699 WXWidget wxFrame::GetMenuBarWidget() const
700 {
701 if (GetMenuBar())
702 return GetMenuBar()->GetMainWidget();
703 else
704 return (WXWidget) NULL;
705 }
706
707 void wxFrame::SetMenuBar(wxMenuBar *menuBar)
708 {
709 if (!menuBar)
710 {
711 m_frameMenuBar = NULL;
712 return;
713 }
714
715 // Currently can't set it twice
716 // wxASSERT_MSG( (m_frameMenuBar == (wxMenuBar*) NULL), "Cannot set the menubar more than once");
717
718 if (m_frameMenuBar)
719 {
720 m_frameMenuBar->DestroyMenuBar();
721 delete m_frameMenuBar;
722 }
723
724 m_frameMenuBar = menuBar;
725 m_frameMenuBar->CreateMenuBar(this);
726 }
727
728 void wxFrame::Fit()
729 {
730 // Work out max. size
731 wxNode *node = GetChildren().First();
732 int max_width = 0;
733 int max_height = 0;
734 while (node)
735 {
736 // Find a child that's a subwindow, but not a dialog box.
737 wxWindow *win = (wxWindow *)node->Data();
738
739 if (!win->IsKindOf(CLASSINFO(wxFrame)) &&
740 !win->IsKindOf(CLASSINFO(wxDialog)))
741 {
742 int width, height;
743 int x, y;
744 win->GetSize(&width, &height);
745 win->GetPosition(&x, &y);
746
747 if ((x + width) > max_width)
748 max_width = x + width;
749 if ((y + height) > max_height)
750 max_height = y + height;
751 }
752 node = node->Next();
753 }
754 SetClientSize(max_width, max_height);
755 }
756
757 // Responds to colour changes, and passes event on to children.
758 void wxFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
759 {
760 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE));
761 Refresh();
762
763 if ( m_frameStatusBar )
764 {
765 wxSysColourChangedEvent event2;
766 event2.SetEventObject( m_frameStatusBar );
767 m_frameStatusBar->ProcessEvent(event2);
768 }
769
770 // Propagate the event to the non-top-level children
771 wxWindow::OnSysColourChanged(event);
772 }
773
774 // Default resizing behaviour - if only ONE subwindow,
775 // resize to client rectangle size
776 void wxFrame::OnSize(wxSizeEvent& WXUNUSED(event))
777 {
778 // if we're using constraints - do use them
779 #if wxUSE_CONSTRAINTS
780 if ( GetAutoLayout() ) {
781 Layout();
782 return;
783 }
784 #endif
785
786 // do we have _exactly_ one child?
787 wxWindow *child = NULL;
788 for ( wxNode *node = GetChildren().First(); node; node = node->Next() )
789 {
790 wxWindow *win = (wxWindow *)node->Data();
791 if ( !win->IsKindOf(CLASSINFO(wxFrame)) &&
792 !win->IsKindOf(CLASSINFO(wxDialog)) &&
793 (win != GetStatusBar())
794 #if wxUSE_TOOLBAR
795 && (win != GetToolBar())
796 #endif // wxUSE_TOOLBAR
797 )
798 {
799 if ( child )
800 return; // it's our second subwindow - nothing to do
801 child = win;
802 }
803 }
804
805 if ( child ) {
806 // we have exactly one child - set it's size to fill the whole frame
807 int clientW, clientH;
808 GetClientSize(&clientW, &clientH);
809
810 int x = 0;
811 int y = 0;
812
813 child->SetSize(x, y, clientW, clientH);
814 }
815 }
816
817 // Default activation behaviour - set the focus for the first child
818 // subwindow found.
819 void wxFrame::OnActivate(wxActivateEvent& event)
820 {
821 if (!event.GetActive())
822 return;
823
824 for(wxNode *node = GetChildren().First(); node; node = node->Next())
825 {
826 // Find a child that's a subwindow, but not a dialog box.
827 wxWindow *child = (wxWindow *)node->Data();
828 if (!child->IsKindOf(CLASSINFO(wxFrame)) &&
829 !child->IsKindOf(CLASSINFO(wxDialog)))
830 {
831 child->SetFocus();
832 return;
833 }
834 }
835 }
836
837 // The default implementation for the close window event.
838 // OnClose for backward compatibility.
839
840 void wxFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
841 {
842 this->Destroy();
843 }
844
845 #ifdef __VMS__
846 // I added this function because I got missing symbols when linking
847 // Maybe it should be included on all platforms. But what should it do?
848 void wxFrame::OnIdle(wxIdleEvent& WXUNUSED(event))
849 {
850 }
851 #endif
852
853 // Destroy the window (delayed, if a managed window)
854 bool wxFrame::Destroy()
855 {
856 if (!wxPendingDelete.Member(this))
857 wxPendingDelete.Append(this);
858 return TRUE;
859 }
860
861 // Default menu selection behaviour - display a help string
862 void wxFrame::OnMenuHighlight(wxMenuEvent& event)
863 {
864 if (GetStatusBar())
865 {
866 if (event.GetMenuId() == -1)
867 SetStatusText("");
868 else
869 {
870 wxMenuBar *menuBar = GetMenuBar();
871 if (menuBar)
872 {
873 wxString helpString(menuBar->GetHelpString(event.GetMenuId()));
874 if (helpString != "")
875 SetStatusText(helpString);
876 }
877 }
878 }
879 }
880
881 wxMenuBar *wxFrame::GetMenuBar() const
882 {
883 return m_frameMenuBar;
884 }
885
886 void wxFrame::Centre(int direction)
887 {
888 int display_width, display_height, width, height, x, y;
889 wxDisplaySize(&display_width, &display_height);
890
891 GetSize(&width, &height);
892 GetPosition(&x, &y);
893
894 if (direction & wxHORIZONTAL)
895 x = (int)((display_width - width)/2);
896 if (direction & wxVERTICAL)
897 y = (int)((display_height - height)/2);
898
899 SetSize(x, y, width, height);
900 }
901
902 // Call this to simulate a menu command
903 void wxFrame::Command(int id)
904 {
905 ProcessCommand(id);
906 }
907
908 void wxFrame::ProcessCommand(int id)
909 {
910 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id);
911 commandEvent.SetInt( id );
912 commandEvent.SetEventObject( this );
913
914 wxMenuBar *bar = GetMenuBar() ;
915 if (!bar)
916 return;
917
918 /* TODO: check the menu item if required
919 wxMenuItem *item = bar->FindItemForId(id) ;
920 if (item && item->IsCheckable())
921 {
922 bar->Check(id,!bar->Checked(id)) ;
923 }
924 */
925
926 wxEvtHandler* evtHandler = GetEventHandler();
927
928 evtHandler->ProcessEvent(commandEvent);
929 }
930
931 // Checks if there is a toolbar, and returns the first free client position
932 wxPoint wxFrame::GetClientAreaOrigin() const
933 {
934 wxPoint pt(0, 0);
935 #if wxUSE_TOOLBAR
936 if (GetToolBar())
937 {
938 int w, h;
939 GetToolBar()->GetSize(& w, & h);
940
941 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL)
942 {
943 pt.x += w;
944 }
945 else
946 {
947 pt.y += h;
948 }
949 }
950 #endif // wxUSE_TOOLBAR
951
952 return pt;
953 }
954
955 void wxFrame::ScreenToClient(int *x, int *y) const
956 {
957 wxWindow::ScreenToClient(x, y);
958
959 // We may be faking the client origin.
960 // So a window that's really at (0, 30) may appear
961 // (to wxWin apps) to be at (0, 0).
962 wxPoint pt(GetClientAreaOrigin());
963 *x -= pt.x;
964 *y -= pt.y;
965 }
966
967 void wxFrame::ClientToScreen(int *x, int *y) const
968 {
969 // We may be faking the client origin.
970 // So a window that's really at (0, 30) may appear
971 // (to wxWin apps) to be at (0, 0).
972 wxPoint pt1(GetClientAreaOrigin());
973 *x += pt1.x;
974 *y += pt1.y;
975
976 wxWindow::ClientToScreen(x, y);
977 }
978
979 #if wxUSE_TOOLBAR
980 wxToolBar* wxFrame::CreateToolBar(long style, wxWindowID id, const wxString& name)
981 {
982 wxCHECK_MSG( m_frameToolBar == NULL, FALSE,
983 "recreating toolbar in wxFrame" );
984
985 wxToolBar* toolBar = OnCreateToolBar(style, id, name);
986 if (toolBar)
987 {
988 SetToolBar(toolBar);
989 PositionToolBar();
990 return toolBar;
991 }
992 else
993 {
994 return NULL;
995 }
996 }
997
998 wxToolBar* wxFrame::OnCreateToolBar(long style, wxWindowID id, const wxString& name)
999 {
1000 return new wxToolBar(this, id, wxPoint(0, 0), wxSize(100, 24), style, name);
1001 }
1002
1003 void wxFrame::SetToolBar(wxToolBar *toolbar)
1004 {
1005 m_frameToolBar = toolbar;
1006 }
1007
1008 wxToolBar *wxFrame::GetToolBar() const
1009 {
1010 return m_frameToolBar;
1011 }
1012
1013 void wxFrame::PositionToolBar()
1014 {
1015 int cw, ch;
1016
1017 GetClientSize(& cw, &ch);
1018
1019 if (GetToolBar())
1020 {
1021 int tw, th;
1022 GetToolBar()->GetSize(& tw, & th);
1023
1024 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL)
1025 {
1026 // Use the 'real' position. wxSIZE_NO_ADJUSTMENTS
1027 // means, pretend we don't have toolbar/status bar, so we
1028 // have the original client size.
1029 GetToolBar()->SetSize(0, 0, tw, ch + th, wxSIZE_NO_ADJUSTMENTS);
1030 }
1031 else
1032 {
1033 // Use the 'real' position
1034 GetToolBar()->SetSize(0, 0, cw, th, wxSIZE_NO_ADJUSTMENTS);
1035 }
1036 }
1037 }
1038 #endif // wxUSE_TOOLBAR
1039
1040 void wxFrame::CaptureMouse()
1041 {
1042 if (m_winCaptured)
1043 return;
1044
1045 if (GetMainWidget())
1046 XtAddGrab((Widget) m_frameShell, TRUE, FALSE);
1047 m_winCaptured = TRUE;
1048 }
1049
1050 void wxFrame::ReleaseMouse()
1051 {
1052 if (!m_winCaptured)
1053 return;
1054
1055 if (GetMainWidget())
1056 XtRemoveGrab((Widget) m_frameShell);
1057 m_winCaptured = FALSE;
1058 }
1059
1060 void wxFrame::Raise(void)
1061 {
1062 Window parent_window = XtWindow((Widget) m_frameShell),
1063 next_parent = XtWindow((Widget) m_frameShell),
1064 root = RootWindowOfScreen(XtScreen((Widget) m_frameShell));
1065 // search for the parent that is child of ROOT, because the WM may
1066 // reparent twice and notify only the next parent (like FVWM)
1067 while (next_parent != root) {
1068 Window *theChildren; unsigned int n;
1069 parent_window = next_parent;
1070 XQueryTree(XtDisplay((Widget) m_frameShell), parent_window, &root,
1071 &next_parent, &theChildren, &n);
1072 XFree(theChildren); // not needed
1073 }
1074 XRaiseWindow(XtDisplay((Widget) m_frameShell), parent_window);
1075 }
1076
1077 void wxFrame::Lower(void)
1078 {
1079 Window parent_window = XtWindow((Widget) m_frameShell),
1080 next_parent = XtWindow((Widget) m_frameShell),
1081 root = RootWindowOfScreen(XtScreen((Widget) m_frameShell));
1082 // search for the parent that is child of ROOT, because the WM may
1083 // reparent twice and notify only the next parent (like FVWM)
1084 while (next_parent != root) {
1085 Window *theChildren; unsigned int n;
1086 parent_window = next_parent;
1087 XQueryTree(XtDisplay((Widget) m_frameShell), parent_window, &root,
1088 &next_parent, &theChildren, &n);
1089 XFree(theChildren); // not needed
1090 }
1091 XLowerWindow(XtDisplay((Widget) m_frameShell), parent_window);
1092 }
1093
1094 void wxFrameFocusProc(Widget WXUNUSED(workArea), XtPointer WXUNUSED(clientData),
1095 XmAnyCallbackStruct *WXUNUSED(cbs))
1096 {
1097 // wxDebugMsg("focus proc from frame %ld\n",(long)frame);
1098 // TODO
1099 // wxFrame *frame = (wxFrame *)clientData;
1100 // frame->GetEventHandler()->OnSetFocus();
1101 }
1102
1103 /* MATTEW: Used to insure that hide-&-show within an event cycle works */
1104 static void wxFrameMapProc(Widget frameShell, XtPointer clientData,
1105 XCrossingEvent * event)
1106 {
1107 wxFrame *frame = (wxFrame *)wxGetWindowFromTable((Widget)clientData);
1108
1109 if (frame) {
1110 XEvent *e = (XEvent *)event;
1111
1112 if (e->xany.type == MapNotify)
1113 {
1114 // Iconize fix
1115 XtVaSetValues(frameShell, XmNiconic, (Boolean)False, NULL);
1116 if (!frame->GetVisibleStatus())
1117 {
1118 /* We really wanted this to be hidden! */
1119 XtUnmapWidget((Widget) frame->GetShellWidget());
1120 }
1121 }
1122 else if (e->xany.type == UnmapNotify)
1123 // Iconize fix
1124 XtVaSetValues(frameShell, XmNiconic, (Boolean)True, NULL);
1125 }
1126 }
1127
1128 //// Motif-specific
1129 bool wxFrame::PreResize()
1130 {
1131 #if wxUSE_TOOLBAR
1132 PositionToolBar();
1133 #endif // wxUSE_TOOLBAR
1134 PositionStatusBar();
1135 return TRUE;
1136 }
1137
1138 WXWidget wxFrame::GetClientWidget() const
1139 {
1140 return m_clientArea;
1141 }
1142
1143 void wxFrame::ChangeFont(bool WXUNUSED(keepOriginalSize))
1144 {
1145 // TODO
1146 }
1147
1148 void wxFrame::ChangeBackgroundColour()
1149 {
1150 if (GetClientWidget())
1151 DoChangeBackgroundColour(GetClientWidget(), m_backgroundColour);
1152 }
1153
1154 void wxFrame::ChangeForegroundColour()
1155 {
1156 if (GetClientWidget())
1157 DoChangeForegroundColour(GetClientWidget(), m_foregroundColour);
1158 }
1159
1160 void wxCloseFrameCallback(Widget WXUNUSED(widget), XtPointer client_data, XmAnyCallbackStruct *WXUNUSED(cbs))
1161 {
1162 wxFrame *frame = (wxFrame *)client_data;
1163
1164 wxCloseEvent closeEvent(wxEVT_CLOSE_WINDOW, frame->GetId());
1165 closeEvent.SetEventObject(frame);
1166
1167 // May delete the frame (with delayed deletion)
1168 frame->GetEventHandler()->ProcessEvent(closeEvent);
1169 }
1170