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"
36 #pragma message disable nosimpint
39 #if defined(__ultrix) || defined(__sgi)
44 #include <X11/Shell.h>
50 #include <Xm/MwmUtil.h>
51 #include <Xm/BulletinB.h>
54 #include <Xm/RowColumn.h>
56 #include <Xm/AtomMgr.h>
57 #include <Xm/LabelG.h>
60 #include <Xm/Protocols.h>
64 #pragma message enable nosimpint
67 #include "wx/motif/private.h"
69 // ----------------------------------------------------------------------------
71 // ----------------------------------------------------------------------------
73 static void wxCloseFrameCallback(Widget
, XtPointer
, XmAnyCallbackStruct
*cbs
);
74 static void wxFrameFocusProc(Widget workArea
, XtPointer clientData
,
75 XmAnyCallbackStruct
*cbs
);
76 static void wxFrameMapProc(Widget frameShell
, XtPointer clientData
,
77 XCrossingEvent
* event
);
79 // ----------------------------------------------------------------------------
81 // ----------------------------------------------------------------------------
83 extern wxList wxModelessWindows
;
84 extern wxList wxPendingDelete
;
86 // TODO: this should be tidied so that any frame can be the
88 static bool wxTopLevelUsed
= FALSE
;
90 // ----------------------------------------------------------------------------
92 // ----------------------------------------------------------------------------
94 #if !USE_SHARED_LIBRARY
95 BEGIN_EVENT_TABLE(wxFrame
, wxFrameBase
)
96 EVT_ACTIVATE(wxFrame::OnActivate
)
97 EVT_SYS_COLOUR_CHANGED(wxFrame::OnSysColourChanged
)
100 IMPLEMENT_DYNAMIC_CLASS(wxFrame
, wxWindow
)
103 // ============================================================================
105 // ============================================================================
107 // ----------------------------------------------------------------------------
108 // frame construction
109 // ----------------------------------------------------------------------------
116 m_frameShell
= (WXWidget
) NULL
;
117 m_frameWidget
= (WXWidget
) NULL
;;
118 m_workArea
= (WXWidget
) NULL
;;
119 m_clientArea
= (WXWidget
) NULL
;;
120 m_visibleStatus
= TRUE
;
123 bool wxFrame::Create(wxWindow
*parent
,
125 const wxString
& title
,
129 const wxString
& name
)
134 wxTopLevelWindows
.Append(this);
136 wxModelessWindows
.Append(this);
140 m_windowStyle
= style
;
142 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
);
143 m_foregroundColour
= *wxBLACK
;
144 m_font
= wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT
);
149 m_windowId
= (int)NewControlId();
151 int x
= pos
.x
, y
= pos
.y
;
152 int width
= size
.x
, height
= size
.y
;
154 // Set reasonable values for position and size if defaults have been
157 // MB TODO: something better than these arbitrary values ?
158 // VZ should use X resources for this...
164 int displayW
, displayH
;
165 wxDisplaySize( &displayW
, &displayH
);
169 x
= (displayW
- width
) / 2;
174 y
= (displayH
- height
) / 2;
178 // VZ: what does this do??
181 // Change suggested by Matthew Flatt
182 m_frameShell
= (WXWidget
)XtAppCreateShell
185 wxTheApp
->GetClassName(),
186 topLevelShellWidgetClass
,
187 (Display
*) wxGetDisplay(),
194 m_frameShell
= wxTheApp
->GetTopLevelWidget();
195 wxTopLevelUsed
= TRUE
;
198 XtVaSetValues((Widget
) m_frameShell
,
199 // Allows menu to resize
200 XmNallowShellResize
, True
,
201 XmNdeleteResponse
, XmDO_NOTHING
,
202 XmNmappedWhenManaged
, False
,
203 XmNiconic
, (style
& wxICONIZE
) ? TRUE
: FALSE
,
206 if (!title
.IsEmpty())
207 XtVaSetValues((Widget
) m_frameShell
,
208 XmNtitle
, title
.c_str(),
211 m_frameWidget
= (WXWidget
) XtVaCreateManagedWidget("main_window",
212 xmMainWindowWidgetClass
, (Widget
) m_frameShell
,
213 XmNresizePolicy
, XmRESIZE_NONE
,
216 m_workArea
= (WXWidget
) XtVaCreateWidget("form",
217 xmFormWidgetClass
, (Widget
) m_frameWidget
,
218 XmNresizePolicy
, XmRESIZE_NONE
,
221 m_clientArea
= (WXWidget
) XtVaCreateWidget("client",
222 xmBulletinBoardWidgetClass
, (Widget
) m_workArea
,
225 XmNrightAttachment
, XmATTACH_FORM
,
226 XmNleftAttachment
, XmATTACH_FORM
,
227 XmNtopAttachment
, XmATTACH_FORM
,
228 XmNbottomAttachment
, XmATTACH_FORM
,
229 // XmNresizePolicy, XmRESIZE_ANY,
232 wxLogTrace(wxTRACE_Messages
,
233 "Created frame (0x%08x) with work area 0x%08x and client "
234 "area 0x%08x", m_frameWidget
, m_workArea
, m_clientArea
);
236 XtAddEventHandler((Widget
) m_clientArea
, ExposureMask
,FALSE
,
237 wxUniversalRepaintProc
, (XtPointer
) this);
239 XtVaSetValues((Widget
) m_frameWidget
,
240 XmNworkWindow
, (Widget
) m_workArea
,
243 XtManageChild((Widget
) m_clientArea
);
244 XtManageChild((Widget
) m_workArea
);
246 wxAddWindowToTable((Widget
) m_workArea
, this);
250 XtOverrideTranslations((Widget
) m_workArea
,
251 ptr
= XtParseTranslationTable("<Configure>: resize()"));
255 XtAddCallback((Widget
) m_workArea
, XmNfocusCallback
,
256 (XtCallbackProc
)wxFrameFocusProc
, (XtPointer
)this);
258 /* Part of show-&-hide fix */
259 XtAddEventHandler((Widget
) m_frameShell
, StructureNotifyMask
,
260 False
, (XtEventHandler
)wxFrameMapProc
,
261 (XtPointer
)m_workArea
);
264 XtVaSetValues((Widget
) m_frameShell
, XmNx
, x
, NULL
);
266 XtVaSetValues((Widget
) m_frameShell
, XmNy
, y
, NULL
);
268 XtVaSetValues((Widget
) m_frameShell
, XmNwidth
, width
, NULL
);
270 XtVaSetValues((Widget
) m_frameShell
, XmNheight
, height
, NULL
);
272 m_mainWidget
= m_frameWidget
;
276 // This patch comes from Torsten Liermann lier@lier1.muc.de
277 if (XmIsMotifWMRunning( (Widget
) m_frameShell
))
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
);
298 // This allows non-Motif window managers to support at least the
299 // no-decorations case.
303 XtVaSetValues((Widget
) m_frameShell
,XmNoverrideRedirect
,TRUE
,NULL
);
305 XtRealizeWidget((Widget
) m_frameShell
);
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);
313 XmAddWMProtocolCallback((Widget
) m_frameShell
, WM_DELETE_WINDOW
, (XtCallbackProc
) wxCloseFrameCallback
, (caddr_t
)this);
315 XmAddWMProtocolCallback((Widget
) m_frameShell
, WM_DELETE_WINDOW
, (void (*)())wxCloseFrameCallback
, (caddr_t
)this);
319 ChangeBackgroundColour();
323 wxSizeEvent
sizeEvent(wxSize(width
, height
), GetId());
324 sizeEvent
.SetEventObject(this);
326 GetEventHandler()->ProcessEvent(sizeEvent
);
333 m_isBeingDeleted
= TRUE
;
336 XtRemoveEventHandler((Widget
) m_clientArea
, ExposureMask
, FALSE
,
337 wxUniversalRepaintProc
, (XtPointer
) this);
344 m_frameMenuBar
->DestroyMenuBar();
346 // Hack to stop core dump on Ultrix, OSF, for some strange reason.
347 #if MOTIF_MENUBAR_DELETE_FIX
348 GetMenuBar()->SetMainWidget((WXWidget
) NULL
);
350 delete m_frameMenuBar
;
351 m_frameMenuBar
= NULL
;
354 wxTopLevelWindows
.DeleteObject(this);
355 wxModelessWindows
.DeleteObject(this);
357 if (m_frameStatusBar
)
359 delete m_frameStatusBar
;
360 m_frameStatusBar
= NULL
;
367 wxDeleteWindowFromTable((Widget
) m_workArea
);
369 XtDestroyWidget ((Widget
) m_workArea
);
374 wxDeleteWindowFromTable((Widget
) m_frameWidget
);
375 XtDestroyWidget ((Widget
) m_frameWidget
);
379 XtDestroyWidget ((Widget
) m_frameShell
);
381 SetMainWidget((WXWidget
) NULL
);
383 /* Check if it's the last top-level window */
385 if (wxTheApp
&& (wxTopLevelWindows
.Number() == 0))
387 wxTheApp
->SetTopWindow(NULL
);
389 if (wxTheApp
->GetExitOnFrameDelete())
391 // Signal to the app that we're going to close
392 wxTheApp
->ExitMainLoop();
397 // Get size *available for subwindows* i.e. excluding menu bar, toolbar etc.
398 void wxFrame::DoGetClientSize(int *x
, int *y
) const
401 XtVaGetValues((Widget
) m_workArea
, XmNwidth
, &xx
, XmNheight
, &yy
, NULL
);
403 if (m_frameStatusBar
)
406 m_frameStatusBar
->GetSize(& sbw
, & sbh
);
413 m_frameToolBar
->GetSize(& tbw
, & tbh
);
414 if (m_frameToolBar
->GetWindowStyleFlag() & wxTB_VERTICAL
)
419 #endif // wxUSE_TOOLBAR
421 if (GetMenuBar() != (wxMenuBar*) NULL)
423 // it seems that if a frame holds a panel, the menu bar size
424 // gets automatically taken care of --- grano@cs.helsinki.fi 4.4.95
425 bool hasSubPanel = FALSE;
426 for(wxNode* node = GetChildren().First(); node; node = node->Next())
428 wxWindow *win = (wxWindow *)node->Data();
429 hasSubPanel = (win->IsKindOf(CLASSINFO(wxPanel)) && !win->IsKindOf(CLASSINFO(wxDialog)));
436 XtVaGetValues((Widget) GetMenuBarWidget(), XmNheight, &ys, NULL);
445 // Set the client size (i.e. leave the calculation of borders etc.
447 void wxFrame::DoSetClientSize(int width
, int height
)
449 // Calculate how large the new main window should be
450 // by finding the difference between the client area and the
451 // main window area, and adding on to the new client area
453 XtVaSetValues((Widget
) m_workArea
, XmNwidth
, width
, NULL
);
457 if (m_frameStatusBar
)
460 m_frameStatusBar
->GetSize(& sbw
, & sbh
);
467 m_frameToolBar
->GetSize(& tbw
, & tbh
);
468 if (m_frameToolBar
->GetWindowStyleFlag() & wxTB_VERTICAL
)
473 #endif // wxUSE_TOOLBAR
475 XtVaSetValues((Widget
) m_workArea
, XmNheight
, height
, NULL
);
479 wxSizeEvent
sizeEvent(wxSize(width
, height
), GetId());
480 sizeEvent
.SetEventObject(this);
482 GetEventHandler()->ProcessEvent(sizeEvent
);
486 void wxFrame::DoGetSize(int *width
, int *height
) const
489 XtVaGetValues((Widget
) m_frameShell
, XmNwidth
, &xx
, XmNheight
, &yy
, NULL
);
490 *width
= xx
; *height
= yy
;
493 void wxFrame::DoGetPosition(int *x
, int *y
) const
495 Window parent_window
= XtWindow((Widget
) m_frameShell
),
496 next_parent
= XtWindow((Widget
) m_frameShell
),
497 root
= RootWindowOfScreen(XtScreen((Widget
) m_frameShell
));
499 // search for the parent that is child of ROOT, because the WM may
500 // reparent twice and notify only the next parent (like FVWM)
501 while (next_parent
!= root
) {
502 Window
*theChildren
; unsigned int n
;
503 parent_window
= next_parent
;
504 XQueryTree(XtDisplay((Widget
) m_frameShell
), parent_window
, &root
,
505 &next_parent
, &theChildren
, &n
);
506 XFree(theChildren
); // not needed
508 int xx
, yy
; unsigned int dummy
;
509 XGetGeometry(XtDisplay((Widget
) m_frameShell
), parent_window
, &root
,
510 &xx
, &yy
, &dummy
, &dummy
, &dummy
, &dummy
);
515 void wxFrame::DoSetSize(int x
, int y
, int width
, int height
, int WXUNUSED(sizeFlags
))
518 XtVaSetValues((Widget
) m_frameShell
, XmNx
, x
, NULL
);
520 XtVaSetValues((Widget
) m_frameShell
, XmNy
, y
, NULL
);
522 XtVaSetValues((Widget
) m_frameWidget
, XmNwidth
, width
, NULL
);
524 XtVaSetValues((Widget
) m_frameWidget
, XmNheight
, height
, NULL
);
526 if (!(height
== -1 && width
== -1))
530 wxSizeEvent
sizeEvent(wxSize(width
, height
), GetId());
531 sizeEvent
.SetEventObject(this);
533 GetEventHandler()->ProcessEvent(sizeEvent
);
537 bool wxFrame::Show(bool show
)
540 return wxWindow::Show(show
);
542 m_visibleStatus
= show
; /* show-&-hide fix */
546 XtMapWidget((Widget
) m_frameShell
);
547 XRaiseWindow(XtDisplay((Widget
) m_frameShell
), XtWindow((Widget
) m_frameShell
));
549 XtUnmapWidget((Widget
) m_frameShell
);
550 // XmUpdateDisplay(wxTheApp->topLevel); // Experimental: may be responsible for crashes
555 void wxFrame::Iconize(bool iconize
)
561 XtVaSetValues((Widget
) m_frameShell
, XmNiconic
, (Boolean
)iconize
, NULL
);
564 void wxFrame::Restore()
567 XtVaSetValues((Widget
) m_frameShell
, XmNiconic
, FALSE
, NULL
);
570 void wxFrame::Maximize(bool maximize
)
578 bool wxFrame::IsIconized() const
584 XtVaGetValues((Widget
) m_frameShell
, XmNiconic
, &iconic
, NULL
);
589 bool wxFrame::IsMaximized() const
591 // No maximizing in Motif (?)
595 void wxFrame::SetTitle(const wxString
& title
)
597 if (title
== m_title
)
603 XtVaSetValues((Widget
) m_frameShell
,
604 XmNtitle
, title
.c_str(),
605 XmNiconName
, title
.c_str(),
609 void wxFrame::SetIcon(const wxIcon
& icon
)
616 if (!icon
.Ok() || !icon
.GetPixmap())
619 XtVaSetValues((Widget
) m_frameShell
, XtNiconPixmap
, icon
.GetPixmap(), NULL
);
622 void wxFrame::PositionStatusBar()
624 if (!m_frameStatusBar
)
628 GetClientSize(&w
, &h
);
630 m_frameStatusBar
->GetSize(&sw
, &sh
);
632 // Since we wish the status bar to be directly under the client area,
633 // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS.
634 m_frameStatusBar
->SetSize(0, h
, w
, sh
);
637 WXWidget
wxFrame::GetMenuBarWidget() const
640 return GetMenuBar()->GetMainWidget();
642 return (WXWidget
) NULL
;
645 void wxFrame::SetMenuBar(wxMenuBar
*menuBar
)
649 m_frameMenuBar
= NULL
;
653 // Currently can't set it twice
654 // wxASSERT_MSG( (m_frameMenuBar == (wxMenuBar*) NULL), "Cannot set the menubar more than once");
658 m_frameMenuBar
->DestroyMenuBar();
659 delete m_frameMenuBar
;
662 m_frameMenuBar
= menuBar
;
663 m_frameMenuBar
->CreateMenuBar(this);
666 // Responds to colour changes, and passes event on to children.
667 void wxFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
669 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
));
672 if ( m_frameStatusBar
)
674 wxSysColourChangedEvent event2
;
675 event2
.SetEventObject( m_frameStatusBar
);
676 m_frameStatusBar
->ProcessEvent(event2
);
679 // Propagate the event to the non-top-level children
680 wxWindow::OnSysColourChanged(event
);
683 // Default activation behaviour - set the focus for the first child
685 void wxFrame::OnActivate(wxActivateEvent
& event
)
687 if (!event
.GetActive())
690 for(wxNode
*node
= GetChildren().First(); node
; node
= node
->Next())
692 // Find a child that's a subwindow, but not a dialog box.
693 wxWindow
*child
= (wxWindow
*)node
->Data();
694 if (!child
->IsKindOf(CLASSINFO(wxFrame
)) &&
695 !child
->IsKindOf(CLASSINFO(wxDialog
)))
705 wxToolBar
* wxFrame::CreateToolBar(long style
,
707 const wxString
& name
)
709 if ( wxFrameBase::CreateToolBar(style
, id
, name
) )
714 return m_frameToolBar
;
717 void wxFrame::PositionToolBar()
722 GetClientSize(& cw
, &ch
);
725 GetToolBar()->GetSize(& tw
, & th
);
727 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL
)
729 // Use the 'real' position. wxSIZE_NO_ADJUSTMENTS
730 // means, pretend we don't have toolbar/status bar, so we
731 // have the original client size.
732 GetToolBar()->SetSize(0, 0, tw
, ch
+ th
, wxSIZE_NO_ADJUSTMENTS
);
736 // Use the 'real' position
737 GetToolBar()->SetSize(0, 0, cw
, th
, wxSIZE_NO_ADJUSTMENTS
);
741 #endif // wxUSE_TOOLBAR
743 void wxFrame::Raise()
745 Window parent_window
= XtWindow((Widget
) m_frameShell
),
746 next_parent
= XtWindow((Widget
) m_frameShell
),
747 root
= RootWindowOfScreen(XtScreen((Widget
) m_frameShell
));
748 // search for the parent that is child of ROOT, because the WM may
749 // reparent twice and notify only the next parent (like FVWM)
750 while (next_parent
!= root
) {
751 Window
*theChildren
; unsigned int n
;
752 parent_window
= next_parent
;
753 XQueryTree(XtDisplay((Widget
) m_frameShell
), parent_window
, &root
,
754 &next_parent
, &theChildren
, &n
);
755 XFree(theChildren
); // not needed
757 XRaiseWindow(XtDisplay((Widget
) m_frameShell
), parent_window
);
760 void wxFrame::Lower()
762 Window parent_window
= XtWindow((Widget
) m_frameShell
),
763 next_parent
= XtWindow((Widget
) m_frameShell
),
764 root
= RootWindowOfScreen(XtScreen((Widget
) m_frameShell
));
765 // search for the parent that is child of ROOT, because the WM may
766 // reparent twice and notify only the next parent (like FVWM)
767 while (next_parent
!= root
) {
768 Window
*theChildren
; unsigned int n
;
769 parent_window
= next_parent
;
770 XQueryTree(XtDisplay((Widget
) m_frameShell
), parent_window
, &root
,
771 &next_parent
, &theChildren
, &n
);
772 XFree(theChildren
); // not needed
774 XLowerWindow(XtDisplay((Widget
) m_frameShell
), parent_window
);
777 void wxFrameFocusProc(Widget
WXUNUSED(workArea
), XtPointer
WXUNUSED(clientData
),
778 XmAnyCallbackStruct
*WXUNUSED(cbs
))
780 // wxDebugMsg("focus proc from frame %ld\n",(long)frame);
782 // wxFrame *frame = (wxFrame *)clientData;
783 // frame->GetEventHandler()->OnSetFocus();
786 /* MATTEW: Used to insure that hide-&-show within an event cycle works */
787 static void wxFrameMapProc(Widget frameShell
, XtPointer clientData
,
788 XCrossingEvent
* event
)
790 wxFrame
*frame
= (wxFrame
*)wxGetWindowFromTable((Widget
)clientData
);
793 XEvent
*e
= (XEvent
*)event
;
795 if (e
->xany
.type
== MapNotify
)
798 XtVaSetValues(frameShell
, XmNiconic
, (Boolean
)False
, NULL
);
799 if (!frame
->GetVisibleStatus())
801 /* We really wanted this to be hidden! */
802 XtUnmapWidget((Widget
) frame
->GetShellWidget());
805 else if (e
->xany
.type
== UnmapNotify
)
807 XtVaSetValues(frameShell
, XmNiconic
, (Boolean
)True
, NULL
);
812 bool wxFrame::PreResize()
816 #endif // wxUSE_TOOLBAR
820 #endif // wxUSE_STATUSBAR
825 WXWidget
wxFrame::GetClientWidget() const
830 void wxFrame::ChangeFont(bool WXUNUSED(keepOriginalSize
))
835 void wxFrame::ChangeBackgroundColour()
837 if (GetClientWidget())
838 DoChangeBackgroundColour(GetClientWidget(), m_backgroundColour
);
841 void wxFrame::ChangeForegroundColour()
843 if (GetClientWidget())
844 DoChangeForegroundColour(GetClientWidget(), m_foregroundColour
);
847 void wxCloseFrameCallback(Widget
WXUNUSED(widget
), XtPointer client_data
, XmAnyCallbackStruct
*WXUNUSED(cbs
))
849 wxFrame
*frame
= (wxFrame
*)client_data
;
851 wxCloseEvent
closeEvent(wxEVT_CLOSE_WINDOW
, frame
->GetId());
852 closeEvent
.SetEventObject(frame
);
854 // May delete the frame (with delayed deletion)
855 frame
->GetEventHandler()->ProcessEvent(closeEvent
);