1 /////////////////////////////////////////////////////////////////////////////
2 // Name: motif/frame.cpp
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "frame.h"
25 #include "wx/statusbr.h"
26 #include "wx/toolbar.h"
27 #include "wx/menuitem.h"
29 #include "wx/dcclient.h"
30 #include "wx/dialog.h"
31 #include "wx/settings.h"
37 #pragma message disable nosimpint
40 #if defined(__ultrix) || defined(__sgi)
45 #include <X11/Shell.h>
51 #include <Xm/MwmUtil.h>
52 #include <Xm/BulletinB.h>
55 #include <Xm/RowColumn.h>
57 #include <Xm/AtomMgr.h>
58 #include <Xm/LabelG.h>
61 #include <Xm/Protocols.h>
65 #pragma message enable nosimpint
68 #include "wx/motif/private.h"
70 // ----------------------------------------------------------------------------
72 // ----------------------------------------------------------------------------
74 static void wxCloseFrameCallback(Widget
, XtPointer
, XmAnyCallbackStruct
*cbs
);
75 static void wxFrameFocusProc(Widget workArea
, XtPointer clientData
,
76 XmAnyCallbackStruct
*cbs
);
77 static void wxFrameMapProc(Widget frameShell
, XtPointer clientData
,
78 XCrossingEvent
* event
);
80 // ----------------------------------------------------------------------------
82 // ----------------------------------------------------------------------------
84 extern wxList wxModelessWindows
;
85 extern wxList wxPendingDelete
;
87 // TODO: this should be tidied so that any frame can be the
89 static bool wxTopLevelUsed
= FALSE
;
91 // ----------------------------------------------------------------------------
93 // ----------------------------------------------------------------------------
95 BEGIN_EVENT_TABLE(wxFrame
, wxFrameBase
)
96 EVT_ACTIVATE(wxFrame::OnActivate
)
97 EVT_SYS_COLOUR_CHANGED(wxFrame::OnSysColourChanged
)
100 IMPLEMENT_DYNAMIC_CLASS(wxFrame
, wxWindow
)
102 // ============================================================================
104 // ============================================================================
106 // ----------------------------------------------------------------------------
107 // frame construction
108 // ----------------------------------------------------------------------------
115 m_frameShell
= (WXWidget
) NULL
;
116 m_frameWidget
= (WXWidget
) NULL
;;
117 m_workArea
= (WXWidget
) NULL
;;
118 m_clientArea
= (WXWidget
) NULL
;;
119 m_visibleStatus
= TRUE
;
122 bool wxFrame::Create(wxWindow
*parent
,
124 const wxString
& title
,
128 const wxString
& name
)
133 wxTopLevelWindows
.Append(this);
135 wxModelessWindows
.Append(this);
139 m_windowStyle
= style
;
141 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
);
142 m_foregroundColour
= *wxBLACK
;
143 m_font
= wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
);
148 m_windowId
= (int)NewControlId();
150 int x
= pos
.x
, y
= pos
.y
;
151 int width
= size
.x
, height
= size
.y
;
153 // Set reasonable values for position and size if defaults have been
156 // MB TODO: something better than these arbitrary values ?
157 // VZ should use X resources for this...
163 int displayW
, displayH
;
164 wxDisplaySize( &displayW
, &displayH
);
168 x
= (displayW
- width
) / 2;
173 y
= (displayH
- height
) / 2;
177 // VZ: what does this do??
180 // Change suggested by Matthew Flatt
181 m_frameShell
= (WXWidget
)XtAppCreateShell
184 wxTheApp
->GetClassName(),
185 topLevelShellWidgetClass
,
186 (Display
*) wxGetDisplay(),
193 m_frameShell
= wxTheApp
->GetTopLevelWidget();
194 wxTopLevelUsed
= TRUE
;
197 XtVaSetValues((Widget
) m_frameShell
,
198 // Allows menu to resize
199 XmNallowShellResize
, True
,
200 XmNdeleteResponse
, XmDO_NOTHING
,
201 XmNmappedWhenManaged
, False
,
202 XmNiconic
, (style
& wxICONIZE
) ? TRUE
: FALSE
,
205 if (!title
.IsEmpty())
206 XtVaSetValues((Widget
) m_frameShell
,
207 XmNtitle
, title
.c_str(),
210 m_frameWidget
= (WXWidget
) XtVaCreateManagedWidget("main_window",
211 xmMainWindowWidgetClass
, (Widget
) m_frameShell
,
212 XmNresizePolicy
, XmRESIZE_NONE
,
215 m_workArea
= (WXWidget
) XtVaCreateWidget("form",
216 xmFormWidgetClass
, (Widget
) m_frameWidget
,
217 XmNresizePolicy
, XmRESIZE_NONE
,
220 m_clientArea
= (WXWidget
) XtVaCreateWidget("client",
221 xmBulletinBoardWidgetClass
, (Widget
) m_workArea
,
224 XmNrightAttachment
, XmATTACH_FORM
,
225 XmNleftAttachment
, XmATTACH_FORM
,
226 XmNtopAttachment
, XmATTACH_FORM
,
227 XmNbottomAttachment
, XmATTACH_FORM
,
228 // XmNresizePolicy, XmRESIZE_ANY,
231 wxLogTrace(wxTRACE_Messages
,
232 "Created frame (0x%08x) with work area 0x%08x and client "
233 "area 0x%08x", m_frameWidget
, m_workArea
, m_clientArea
);
235 XtAddEventHandler((Widget
) m_clientArea
, ExposureMask
,FALSE
,
236 wxUniversalRepaintProc
, (XtPointer
) this);
238 XtVaSetValues((Widget
) m_frameWidget
,
239 XmNworkWindow
, (Widget
) m_workArea
,
242 XtManageChild((Widget
) m_clientArea
);
243 XtManageChild((Widget
) m_workArea
);
245 wxAddWindowToTable((Widget
) m_workArea
, this);
249 XtOverrideTranslations((Widget
) m_workArea
,
250 ptr
= XtParseTranslationTable("<Configure>: resize()"));
254 XtAddCallback((Widget
) m_workArea
, XmNfocusCallback
,
255 (XtCallbackProc
)wxFrameFocusProc
, (XtPointer
)this);
257 /* Part of show-&-hide fix */
258 XtAddEventHandler((Widget
) m_frameShell
, StructureNotifyMask
,
259 False
, (XtEventHandler
)wxFrameMapProc
,
260 (XtPointer
)m_workArea
);
263 XtVaSetValues((Widget
) m_frameShell
, XmNx
, x
, NULL
);
265 XtVaSetValues((Widget
) m_frameShell
, XmNy
, y
, NULL
);
267 XtVaSetValues((Widget
) m_frameShell
, XmNwidth
, width
, NULL
);
269 XtVaSetValues((Widget
) m_frameShell
, XmNheight
, height
, NULL
);
271 m_mainWidget
= m_frameWidget
;
275 // This patch comes from Torsten Liermann lier@lier1.muc.de
276 if (XmIsMotifWMRunning( (Widget
) m_frameShell
))
279 if (style
& wxRESIZE_BORDER
)
280 decor
|= MWM_DECOR_RESIZEH
;
281 if (style
& wxSYSTEM_MENU
)
282 decor
|= MWM_DECOR_MENU
;
283 if ((style
& wxCAPTION
) ||
284 (style
& wxTINY_CAPTION_HORIZ
) ||
285 (style
& wxTINY_CAPTION_VERT
))
286 decor
|= MWM_DECOR_TITLE
;
287 if (style
& wxTHICK_FRAME
)
288 decor
|= MWM_DECOR_BORDER
;
289 if (style
& wxTHICK_FRAME
)
290 decor
|= MWM_DECOR_BORDER
;
291 if (style
& wxMINIMIZE_BOX
)
292 decor
|= MWM_DECOR_MINIMIZE
;
293 if (style
& wxMAXIMIZE_BOX
)
294 decor
|= MWM_DECOR_MAXIMIZE
;
295 XtVaSetValues((Widget
) m_frameShell
,XmNmwmDecorations
,decor
,NULL
);
297 // This allows non-Motif window managers to support at least the
298 // no-decorations case.
302 XtVaSetValues((Widget
) m_frameShell
,XmNoverrideRedirect
,TRUE
,NULL
);
304 XtRealizeWidget((Widget
) m_frameShell
);
306 // Intercept CLOSE messages from the window manager
307 Atom WM_DELETE_WINDOW
= XmInternAtom(XtDisplay((Widget
) m_frameShell
), "WM_DELETE_WINDOW", False
);
308 #if (XmREVISION > 1 || XmVERSION > 1)
309 XmAddWMProtocolCallback((Widget
) m_frameShell
, WM_DELETE_WINDOW
, (XtCallbackProc
) wxCloseFrameCallback
, (XtPointer
)this);
312 XmAddWMProtocolCallback((Widget
) m_frameShell
, WM_DELETE_WINDOW
, (XtCallbackProc
) wxCloseFrameCallback
, (caddr_t
)this);
314 XmAddWMProtocolCallback((Widget
) m_frameShell
, WM_DELETE_WINDOW
, (void (*)())wxCloseFrameCallback
, (caddr_t
)this);
318 ChangeBackgroundColour();
322 wxSizeEvent
sizeEvent(wxSize(width
, height
), GetId());
323 sizeEvent
.SetEventObject(this);
325 GetEventHandler()->ProcessEvent(sizeEvent
);
332 m_isBeingDeleted
= TRUE
;
335 XtRemoveEventHandler((Widget
) m_clientArea
, ExposureMask
, FALSE
,
336 wxUniversalRepaintProc
, (XtPointer
) this);
343 m_frameMenuBar
->DestroyMenuBar();
345 // Hack to stop core dump on Ultrix, OSF, for some strange reason.
346 #if MOTIF_MENUBAR_DELETE_FIX
347 GetMenuBar()->SetMainWidget((WXWidget
) NULL
);
349 delete m_frameMenuBar
;
350 m_frameMenuBar
= NULL
;
353 wxTopLevelWindows
.DeleteObject(this);
354 wxModelessWindows
.DeleteObject(this);
356 if (m_frameStatusBar
)
358 delete m_frameStatusBar
;
359 m_frameStatusBar
= NULL
;
366 wxDeleteWindowFromTable((Widget
) m_workArea
);
368 XtDestroyWidget ((Widget
) m_workArea
);
373 wxDeleteWindowFromTable((Widget
) m_frameWidget
);
374 XtDestroyWidget ((Widget
) m_frameWidget
);
378 XtDestroyWidget ((Widget
) m_frameShell
);
380 SetMainWidget((WXWidget
) NULL
);
382 /* Check if it's the last top-level window */
384 if (wxTheApp
&& (wxTopLevelWindows
.Number() == 0))
386 wxTheApp
->SetTopWindow(NULL
);
388 if (wxTheApp
->GetExitOnFrameDelete())
390 // Signal to the app that we're going to close
391 wxTheApp
->ExitMainLoop();
396 // Get size *available for subwindows* i.e. excluding menu bar, toolbar etc.
397 void wxFrame::DoGetClientSize(int *x
, int *y
) const
400 XtVaGetValues((Widget
) m_workArea
, XmNwidth
, &xx
, XmNheight
, &yy
, NULL
);
402 if (m_frameStatusBar
)
405 m_frameStatusBar
->GetSize(& sbw
, & sbh
);
412 m_frameToolBar
->GetSize(& tbw
, & tbh
);
413 if (m_frameToolBar
->GetWindowStyleFlag() & wxTB_VERTICAL
)
418 #endif // wxUSE_TOOLBAR
420 if (GetMenuBar() != (wxMenuBar*) NULL)
422 // it seems that if a frame holds a panel, the menu bar size
423 // gets automatically taken care of --- grano@cs.helsinki.fi 4.4.95
424 bool hasSubPanel = FALSE;
425 for(wxNode* node = GetChildren().First(); node; node = node->Next())
427 wxWindow *win = (wxWindow *)node->Data();
428 hasSubPanel = (win->IsKindOf(CLASSINFO(wxPanel)) && !win->IsKindOf(CLASSINFO(wxDialog)));
435 XtVaGetValues((Widget) GetMenuBarWidget(), XmNheight, &ys, NULL);
444 // Set the client size (i.e. leave the calculation of borders etc.
446 void wxFrame::DoSetClientSize(int width
, int height
)
448 // Calculate how large the new main window should be
449 // by finding the difference between the client area and the
450 // main window area, and adding on to the new client area
452 XtVaSetValues((Widget
) m_workArea
, XmNwidth
, width
, NULL
);
456 if (m_frameStatusBar
)
459 m_frameStatusBar
->GetSize(& sbw
, & sbh
);
466 m_frameToolBar
->GetSize(& tbw
, & tbh
);
467 if (m_frameToolBar
->GetWindowStyleFlag() & wxTB_VERTICAL
)
472 #endif // wxUSE_TOOLBAR
474 XtVaSetValues((Widget
) m_workArea
, XmNheight
, height
, NULL
);
478 wxSizeEvent
sizeEvent(wxSize(width
, height
), GetId());
479 sizeEvent
.SetEventObject(this);
481 GetEventHandler()->ProcessEvent(sizeEvent
);
485 void wxFrame::DoGetSize(int *width
, int *height
) const
488 XtVaGetValues((Widget
) m_frameShell
, XmNwidth
, &xx
, XmNheight
, &yy
, NULL
);
489 *width
= xx
; *height
= yy
;
492 void wxFrame::DoGetPosition(int *x
, int *y
) const
494 Window parent_window
= XtWindow((Widget
) m_frameShell
),
495 next_parent
= XtWindow((Widget
) m_frameShell
),
496 root
= RootWindowOfScreen(XtScreen((Widget
) m_frameShell
));
498 // search for the parent that is child of ROOT, because the WM may
499 // reparent twice and notify only the next parent (like FVWM)
500 while (next_parent
!= root
) {
501 Window
*theChildren
; unsigned int n
;
502 parent_window
= next_parent
;
503 XQueryTree(XtDisplay((Widget
) m_frameShell
), parent_window
, &root
,
504 &next_parent
, &theChildren
, &n
);
505 XFree(theChildren
); // not needed
507 int xx
, yy
; unsigned int dummy
;
508 XGetGeometry(XtDisplay((Widget
) m_frameShell
), parent_window
, &root
,
509 &xx
, &yy
, &dummy
, &dummy
, &dummy
, &dummy
);
514 void wxFrame::DoSetSize(int x
, int y
, int width
, int height
, int WXUNUSED(sizeFlags
))
517 XtVaSetValues((Widget
) m_frameShell
, XmNx
, x
, NULL
);
519 XtVaSetValues((Widget
) m_frameShell
, XmNy
, y
, NULL
);
521 XtVaSetValues((Widget
) m_frameWidget
, XmNwidth
, width
, NULL
);
523 XtVaSetValues((Widget
) m_frameWidget
, XmNheight
, height
, NULL
);
525 if (!(height
== -1 && width
== -1))
529 wxSizeEvent
sizeEvent(wxSize(width
, height
), GetId());
530 sizeEvent
.SetEventObject(this);
532 GetEventHandler()->ProcessEvent(sizeEvent
);
536 bool wxFrame::Show(bool show
)
539 return wxWindow::Show(show
);
541 m_visibleStatus
= show
; /* show-&-hide fix */
545 XtMapWidget((Widget
) m_frameShell
);
546 XRaiseWindow(XtDisplay((Widget
) m_frameShell
), XtWindow((Widget
) m_frameShell
));
548 XtUnmapWidget((Widget
) m_frameShell
);
549 // XmUpdateDisplay(wxTheApp->topLevel); // Experimental: may be responsible for crashes
554 void wxFrame::Iconize(bool iconize
)
560 XtVaSetValues((Widget
) m_frameShell
, XmNiconic
, (Boolean
)iconize
, NULL
);
563 void wxFrame::Restore()
566 XtVaSetValues((Widget
) m_frameShell
, XmNiconic
, FALSE
, NULL
);
569 void wxFrame::Maximize(bool maximize
)
577 bool wxFrame::IsIconized() const
583 XtVaGetValues((Widget
) m_frameShell
, XmNiconic
, &iconic
, NULL
);
588 bool wxFrame::IsMaximized() const
590 // No maximizing in Motif (?)
594 void wxFrame::SetTitle(const wxString
& title
)
596 if (title
== m_title
)
602 XtVaSetValues((Widget
) m_frameShell
,
603 XmNtitle
, title
.c_str(),
604 XmNiconName
, title
.c_str(),
608 void wxFrame::SetIcon(const wxIcon
& icon
)
615 if (!icon
.Ok() || !icon
.GetPixmap())
618 XtVaSetValues((Widget
) m_frameShell
, XtNiconPixmap
, icon
.GetPixmap(), NULL
);
621 void wxFrame::PositionStatusBar()
623 if (!m_frameStatusBar
)
627 GetClientSize(&w
, &h
);
629 m_frameStatusBar
->GetSize(&sw
, &sh
);
631 // Since we wish the status bar to be directly under the client area,
632 // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS.
633 m_frameStatusBar
->SetSize(0, h
, w
, sh
);
636 WXWidget
wxFrame::GetMenuBarWidget() const
639 return GetMenuBar()->GetMainWidget();
641 return (WXWidget
) NULL
;
644 void wxFrame::SetMenuBar(wxMenuBar
*menuBar
)
648 m_frameMenuBar
= NULL
;
652 // Currently can't set it twice
653 // wxASSERT_MSG( (m_frameMenuBar == (wxMenuBar*) NULL), "Cannot set the menubar more than once");
657 m_frameMenuBar
->DestroyMenuBar();
658 delete m_frameMenuBar
;
661 m_frameMenuBar
= menuBar
;
662 m_frameMenuBar
->CreateMenuBar(this);
665 // Responds to colour changes, and passes event on to children.
666 void wxFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
668 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
));
671 if ( m_frameStatusBar
)
673 wxSysColourChangedEvent event2
;
674 event2
.SetEventObject( m_frameStatusBar
);
675 m_frameStatusBar
->ProcessEvent(event2
);
678 // Propagate the event to the non-top-level children
679 wxWindow::OnSysColourChanged(event
);
682 // Default activation behaviour - set the focus for the first child
684 void wxFrame::OnActivate(wxActivateEvent
& event
)
686 if (!event
.GetActive())
689 for(wxNode
*node
= GetChildren().First(); node
; node
= node
->Next())
691 // Find a child that's a subwindow, but not a dialog box.
692 wxWindow
*child
= (wxWindow
*)node
->Data();
693 if (!child
->IsKindOf(CLASSINFO(wxFrame
)) &&
694 !child
->IsKindOf(CLASSINFO(wxDialog
)))
704 wxToolBar
* wxFrame::CreateToolBar(long style
,
706 const wxString
& name
)
708 if ( wxFrameBase::CreateToolBar(style
, id
, name
) )
713 return m_frameToolBar
;
716 void wxFrame::PositionToolBar()
721 GetClientSize(& cw
, &ch
);
724 GetToolBar()->GetSize(& tw
, & th
);
726 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL
)
728 // Use the 'real' position. wxSIZE_NO_ADJUSTMENTS
729 // means, pretend we don't have toolbar/status bar, so we
730 // have the original client size.
731 GetToolBar()->SetSize(0, 0, tw
, ch
+ th
, wxSIZE_NO_ADJUSTMENTS
);
735 // Use the 'real' position
736 GetToolBar()->SetSize(0, 0, cw
, th
, wxSIZE_NO_ADJUSTMENTS
);
740 #endif // wxUSE_TOOLBAR
742 void wxFrame::Raise()
744 Window parent_window
= XtWindow((Widget
) m_frameShell
),
745 next_parent
= XtWindow((Widget
) m_frameShell
),
746 root
= RootWindowOfScreen(XtScreen((Widget
) m_frameShell
));
747 // search for the parent that is child of ROOT, because the WM may
748 // reparent twice and notify only the next parent (like FVWM)
749 while (next_parent
!= root
) {
750 Window
*theChildren
; unsigned int n
;
751 parent_window
= next_parent
;
752 XQueryTree(XtDisplay((Widget
) m_frameShell
), parent_window
, &root
,
753 &next_parent
, &theChildren
, &n
);
754 XFree(theChildren
); // not needed
756 XRaiseWindow(XtDisplay((Widget
) m_frameShell
), parent_window
);
759 void wxFrame::Lower()
761 Window parent_window
= XtWindow((Widget
) m_frameShell
),
762 next_parent
= XtWindow((Widget
) m_frameShell
),
763 root
= RootWindowOfScreen(XtScreen((Widget
) m_frameShell
));
764 // search for the parent that is child of ROOT, because the WM may
765 // reparent twice and notify only the next parent (like FVWM)
766 while (next_parent
!= root
) {
767 Window
*theChildren
; unsigned int n
;
768 parent_window
= next_parent
;
769 XQueryTree(XtDisplay((Widget
) m_frameShell
), parent_window
, &root
,
770 &next_parent
, &theChildren
, &n
);
771 XFree(theChildren
); // not needed
773 XLowerWindow(XtDisplay((Widget
) m_frameShell
), parent_window
);
776 void wxFrameFocusProc(Widget
WXUNUSED(workArea
), XtPointer
WXUNUSED(clientData
),
777 XmAnyCallbackStruct
*WXUNUSED(cbs
))
779 // wxDebugMsg("focus proc from frame %ld\n",(long)frame);
781 // wxFrame *frame = (wxFrame *)clientData;
782 // frame->GetEventHandler()->OnSetFocus();
785 /* MATTEW: Used to insure that hide-&-show within an event cycle works */
786 static void wxFrameMapProc(Widget frameShell
, XtPointer clientData
,
787 XCrossingEvent
* event
)
789 wxFrame
*frame
= (wxFrame
*)wxGetWindowFromTable((Widget
)clientData
);
792 XEvent
*e
= (XEvent
*)event
;
794 if (e
->xany
.type
== MapNotify
)
797 XtVaSetValues(frameShell
, XmNiconic
, (Boolean
)False
, NULL
);
798 if (!frame
->GetVisibleStatus())
800 /* We really wanted this to be hidden! */
801 XtUnmapWidget((Widget
) frame
->GetShellWidget());
804 else if (e
->xany
.type
== UnmapNotify
)
806 XtVaSetValues(frameShell
, XmNiconic
, (Boolean
)True
, NULL
);
811 bool wxFrame::PreResize()
815 #endif // wxUSE_TOOLBAR
819 #endif // wxUSE_STATUSBAR
824 WXWidget
wxFrame::GetClientWidget() const
829 void wxFrame::ChangeFont(bool WXUNUSED(keepOriginalSize
))
834 void wxFrame::ChangeBackgroundColour()
836 if (GetClientWidget())
837 DoChangeBackgroundColour(GetClientWidget(), m_backgroundColour
);
840 void wxFrame::ChangeForegroundColour()
842 if (GetClientWidget())
843 DoChangeForegroundColour(GetClientWidget(), m_foregroundColour
);
846 void wxCloseFrameCallback(Widget
WXUNUSED(widget
), XtPointer client_data
, XmAnyCallbackStruct
*WXUNUSED(cbs
))
848 wxFrame
*frame
= (wxFrame
*)client_data
;
850 wxCloseEvent
closeEvent(wxEVT_CLOSE_WINDOW
, frame
->GetId());
851 closeEvent
.SetEventObject(frame
);
853 // May delete the frame (with delayed deletion)
854 frame
->GetEventHandler()->ProcessEvent(closeEvent
);