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