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