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