Motif compile fixes
[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 extern wxHashTable *wxWidgetHashTable;
54
55 void wxCloseFrameCallback(Widget, XtPointer, XmAnyCallbackStruct *cbs);
56 void wxFrameFocusProc(Widget workArea, XtPointer clientData,
57 XmAnyCallbackStruct *cbs);
58 static void wxFrameMapProc(Widget frameShell, XtPointer clientData,
59 XCrossingEvent * event);
60
61 extern wxList wxModelessWindows;
62 extern wxList wxPendingDelete;
63
64 // TODO: this should be tidied so that any frame can be the
65 // top frame
66 static bool wxTopLevelUsed = FALSE;
67
68 #if !USE_SHARED_LIBRARY
69 BEGIN_EVENT_TABLE(wxFrame, wxWindow)
70 EVT_SIZE(wxFrame::OnSize)
71 EVT_ACTIVATE(wxFrame::OnActivate)
72 EVT_MENU_HIGHLIGHT_ALL(wxFrame::OnMenuHighlight)
73 EVT_SYS_COLOUR_CHANGED(wxFrame::OnSysColourChanged)
74 EVT_IDLE(wxFrame::OnIdle)
75 EVT_CLOSE(wxFrame::OnCloseWindow)
76 END_EVENT_TABLE()
77
78 IMPLEMENT_DYNAMIC_CLASS(wxFrame, wxWindow)
79 #endif
80
81 #if wxUSE_NATIVE_STATUSBAR
82 bool wxFrame::m_useNativeStatusBar = TRUE;
83 #else
84 bool wxFrame::m_useNativeStatusBar = FALSE;
85 #endif
86
87 wxFrame::wxFrame()
88 {
89 #if wxUSE_TOOLBAR
90 m_frameToolBar = NULL ;
91 #endif // wxUSE_TOOLBAR
92
93 m_frameMenuBar = NULL;
94 m_frameStatusBar = NULL;
95
96 m_parent = NULL;
97 m_iconized = FALSE;
98
99 //// Motif-specific
100 m_frameShell = (WXWidget) NULL;
101 m_frameWidget = (WXWidget) NULL;;
102 m_workArea = (WXWidget) NULL;;
103 m_clientArea = (WXWidget) NULL;;
104 m_visibleStatus = TRUE;
105 m_title = "";
106 }
107
108 bool wxFrame::Create(wxWindow *parent,
109 wxWindowID id,
110 const wxString& title,
111 const wxPoint& pos,
112 const wxSize& size,
113 long style,
114 const wxString& name)
115 {
116 if (!parent)
117 wxTopLevelWindows.Append(this);
118
119 SetName(name);
120
121 m_windowStyle = style;
122 m_frameMenuBar = NULL;
123 #if wxUSE_TOOLBAR
124 m_frameToolBar = NULL ;
125 #endif // wxUSE_TOOLBAR
126 m_frameStatusBar = NULL;
127
128 //// Motif-specific
129 m_frameShell = (WXWidget) NULL;
130 m_frameWidget = (WXWidget) NULL;;
131 m_workArea = (WXWidget) NULL;;
132 m_clientArea = (WXWidget) NULL;;
133 m_visibleStatus = TRUE;
134 m_title = "";
135
136 m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE);
137 m_foregroundColour = *wxBLACK;
138 m_font = wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT);
139
140 if ( id > -1 )
141 m_windowId = id;
142 else
143 m_windowId = (int)NewControlId();
144
145 if (parent) parent->AddChild(this);
146
147 wxModelessWindows.Append(this);
148
149 int x = pos.x; int y = pos.y;
150 int width = size.x; int height = size.y;
151
152 if (wxTopLevelUsed)
153 // Change suggested by Matthew Flatt
154 m_frameShell = (WXWidget) XtAppCreateShell(name, wxTheApp->GetClassName(), topLevelShellWidgetClass, (Display*) wxGetDisplay(), NULL, 0);
155 else
156 {
157 m_frameShell = wxTheApp->GetTopLevelWidget();
158 wxTopLevelUsed = TRUE;
159 }
160
161 XtVaSetValues((Widget) m_frameShell,
162 // Allows menu to resize
163 XmNallowShellResize, True,
164 XmNdeleteResponse, XmDO_NOTHING,
165 XmNmappedWhenManaged, False,
166 XmNiconic, (style & wxICONIZE) ? TRUE : FALSE,
167 NULL);
168
169 if (!title.IsNull())
170 XtVaSetValues((Widget) m_frameShell,
171 XmNtitle, (const char*) title,
172 NULL);
173
174 m_frameWidget = (WXWidget) XtVaCreateManagedWidget("main_window",
175 xmMainWindowWidgetClass, (Widget) m_frameShell,
176 XmNresizePolicy, XmRESIZE_NONE,
177 NULL);
178
179 m_workArea = (WXWidget) XtVaCreateWidget("form",
180 xmFormWidgetClass, (Widget) m_frameWidget,
181 XmNresizePolicy, XmRESIZE_NONE,
182 NULL);
183
184 m_clientArea = (WXWidget) XtVaCreateWidget("client",
185 xmBulletinBoardWidgetClass, (Widget) m_workArea,
186 XmNmarginWidth, 0,
187 XmNmarginHeight, 0,
188 XmNrightAttachment, XmATTACH_FORM,
189 XmNleftAttachment, XmATTACH_FORM,
190 XmNtopAttachment, XmATTACH_FORM,
191 XmNbottomAttachment, XmATTACH_FORM,
192 // XmNresizePolicy, XmRESIZE_ANY,
193 NULL);
194
195 XtAddEventHandler((Widget) m_clientArea, ExposureMask,FALSE,
196 wxUniversalRepaintProc, (XtPointer) this);
197
198 XtVaSetValues((Widget) m_frameWidget,
199 XmNworkWindow, (Widget) m_workArea,
200 NULL);
201
202 XtManageChild((Widget) m_clientArea);
203 XtManageChild((Widget) m_workArea);
204
205 wxASSERT_MSG ((wxWidgetHashTable->Get((long)m_workArea) == (wxObject*) NULL), "Widget table clash in frame.cpp") ;
206
207 wxAddWindowToTable((Widget) m_workArea, this);
208
209 XtTranslations ptr ;
210
211 XtOverrideTranslations((Widget) m_workArea,
212 ptr = XtParseTranslationTable("<Configure>: resize()"));
213
214 XtFree((char *)ptr);
215
216 XtAddCallback((Widget) m_workArea, XmNfocusCallback,
217 (XtCallbackProc)wxFrameFocusProc, (XtPointer)this);
218
219 /* Part of show-&-hide fix */
220 XtAddEventHandler((Widget) m_frameShell, StructureNotifyMask,
221 False, (XtEventHandler)wxFrameMapProc,
222 (XtPointer)m_workArea);
223
224 if (x > -1)
225 XtVaSetValues((Widget) m_frameShell, XmNx, x, NULL);
226 if (y > -1)
227 XtVaSetValues((Widget) m_frameShell, XmNy, y, NULL);
228 if (width > -1)
229 XtVaSetValues((Widget) m_frameShell, XmNwidth, width, NULL);
230 if (height > -1)
231 XtVaSetValues((Widget) m_frameShell, XmNheight, height, NULL);
232
233 m_mainWidget = m_frameWidget;
234
235 ChangeFont(FALSE);
236
237 // This patch comes from Torsten Liermann lier@lier1.muc.de
238 if (XmIsMotifWMRunning( (Widget) m_frameShell ))
239 {
240 int decor = 0 ;
241 if (style & wxRESIZE_BORDER)
242 decor |= MWM_DECOR_RESIZEH ;
243 if (style & wxSYSTEM_MENU)
244 decor |= MWM_DECOR_MENU;
245 if ((style & wxCAPTION) ||
246 (style & wxTINY_CAPTION_HORIZ) ||
247 (style & wxTINY_CAPTION_VERT))
248 decor |= MWM_DECOR_TITLE;
249 if (style & wxTHICK_FRAME)
250 decor |= MWM_DECOR_BORDER;
251 if (style & wxTHICK_FRAME)
252 decor |= MWM_DECOR_BORDER;
253 if (style & wxMINIMIZE_BOX)
254 decor |= MWM_DECOR_MINIMIZE;
255 if (style & wxMAXIMIZE_BOX)
256 decor |= MWM_DECOR_MAXIMIZE;
257 XtVaSetValues((Widget) m_frameShell,XmNmwmDecorations,decor,NULL) ;
258 }
259 // This allows non-Motif window managers to support at least the
260 // no-decorations case.
261 else
262 {
263 if (style == 0)
264 XtVaSetValues((Widget) m_frameShell,XmNoverrideRedirect,TRUE,NULL);
265 }
266 XtRealizeWidget((Widget) m_frameShell);
267
268 // Intercept CLOSE messages from the window manager
269 Atom WM_DELETE_WINDOW = XmInternAtom(XtDisplay((Widget) m_frameShell), "WM_DELETE_WINDOW", False);
270 #if (XmREVISION > 1 || XmVERSION > 1)
271 XmAddWMProtocolCallback((Widget) m_frameShell, WM_DELETE_WINDOW, (XtCallbackProc) wxCloseFrameCallback, (XtPointer)this);
272 #else
273 #if XmREVISION == 1
274 XmAddWMProtocolCallback((Widget) m_frameShell, WM_DELETE_WINDOW, (XtCallbackProc) wxCloseFrameCallback, (caddr_t)this);
275 #else
276 XmAddWMProtocolCallback((Widget) m_frameShell, WM_DELETE_WINDOW, (void (*)())wxCloseFrameCallback, (caddr_t)this);
277 #endif
278 #endif
279
280 ChangeBackgroundColour();
281
282 PreResize();
283
284 wxSizeEvent sizeEvent(wxSize(width, height), GetId());
285 sizeEvent.SetEventObject(this);
286
287 GetEventHandler()->ProcessEvent(sizeEvent);
288
289 return TRUE;
290 }
291
292 wxFrame::~wxFrame()
293 {
294 if (m_clientArea)
295 XtRemoveEventHandler((Widget) m_clientArea, ExposureMask, FALSE,
296 wxUniversalRepaintProc, (XtPointer) this);
297
298 if (GetMainWidget())
299 Show(FALSE);
300
301 if (m_frameMenuBar)
302 {
303 m_frameMenuBar->DestroyMenuBar();
304
305 // Hack to stop core dump on Ultrix, OSF, for some strange reason.
306 #if MOTIF_MENUBAR_DELETE_FIX
307 GetMenuBar()->SetMainWidget((WXWidget) NULL);
308 #endif
309 delete m_frameMenuBar;
310 m_frameMenuBar = NULL;
311 }
312
313 wxTopLevelWindows.DeleteObject(this);
314 wxModelessWindows.DeleteObject(this);
315
316 if (m_frameStatusBar)
317 delete m_frameStatusBar;
318
319 DestroyChildren();
320
321 /*
322 int i;
323 for (i = 0; i < wxMAX_STATUS; i++)
324 if (statusTextWidget[i])
325 XtDestroyWidget (statusTextWidget[i]);
326
327 if (statusLineForm)
328 XtDestroyWidget (statusLineForm);
329
330 if (statusLineWidget)
331 XtDestroyWidget (statusLineWidget);
332 */
333
334 if (m_workArea)
335 {
336 wxDeleteWindowFromTable((Widget) m_workArea);
337
338 XtDestroyWidget ((Widget) m_workArea);
339 }
340
341 if (m_frameWidget)
342 {
343 wxDeleteWindowFromTable((Widget) m_frameWidget);
344 XtDestroyWidget ((Widget) m_frameWidget);
345 }
346
347 if (m_frameShell)
348 XtDestroyWidget ((Widget) m_frameShell);
349
350 SetMainWidget((WXWidget) NULL);
351
352 /* Check if it's the last top-level window */
353
354 if (wxTheApp && (wxTopLevelWindows.Number() == 0))
355 {
356 wxTheApp->SetTopWindow(NULL);
357
358 if (wxTheApp->GetExitOnFrameDelete())
359 {
360 // Signal to the app that we're going to close
361 wxTheApp->ExitMainLoop();
362 }
363 }
364
365 }
366
367 // Get size *available for subwindows* i.e. excluding menu bar, toolbar etc.
368 void wxFrame::GetClientSize(int *x, int *y) const
369 {
370 Dimension xx, yy;
371 XtVaGetValues((Widget) m_workArea, XmNwidth, &xx, XmNheight, &yy, NULL);
372
373 if (m_frameStatusBar)
374 {
375 int sbw, sbh;
376 m_frameStatusBar->GetSize(& sbw, & sbh);
377 yy -= sbh;
378 }
379 #if wxUSE_TOOLBAR
380 if (m_frameToolBar)
381 {
382 int tbw, tbh;
383 m_frameToolBar->GetSize(& tbw, & tbh);
384 if (m_frameToolBar->GetWindowStyleFlag() & wxTB_VERTICAL)
385 xx -= tbw;
386 else
387 yy -= tbh;
388 }
389 #endif // wxUSE_TOOLBAR
390 /*
391 if (GetMenuBar() != (wxMenuBar*) NULL)
392 {
393 // it seems that if a frame holds a panel, the menu bar size
394 // gets automatically taken care of --- grano@cs.helsinki.fi 4.4.95
395 bool hasSubPanel = FALSE;
396 for(wxNode* node = GetChildren().First(); node; node = node->Next())
397 {
398 wxWindow *win = (wxWindow *)node->Data();
399 hasSubPanel = (win->IsKindOf(CLASSINFO(wxPanel)) && !win->IsKindOf(CLASSINFO(wxDialog)));
400
401 if (hasSubPanel)
402 break;
403 }
404 if (! hasSubPanel) {
405 Dimension ys;
406 XtVaGetValues((Widget) GetMenuBarWidget(), XmNheight, &ys, NULL);
407 yy -= ys;
408 }
409 }
410 */
411
412 *x = xx; *y = yy;
413 }
414
415 // Set the client size (i.e. leave the calculation of borders etc.
416 // to wxWindows)
417 void wxFrame::DoSetClientSize(int width, int height)
418 {
419 // Calculate how large the new main window should be
420 // by finding the difference between the client area and the
421 // main window area, and adding on to the new client area
422 if (width > -1)
423 XtVaSetValues((Widget) m_workArea, XmNwidth, width, NULL);
424
425 if (height > -1)
426 {
427 if (m_frameStatusBar)
428 {
429 int sbw, sbh;
430 m_frameStatusBar->GetSize(& sbw, & sbh);
431 height += sbh;
432 }
433 #if wxUSE_TOOLBAR
434 if (m_frameToolBar)
435 {
436 int tbw, tbh;
437 m_frameToolBar->GetSize(& tbw, & tbh);
438 if (m_frameToolBar->GetWindowStyleFlag() & wxTB_VERTICAL)
439 width += tbw;
440 else
441 height += tbh;
442 }
443 #endif // wxUSE_TOOLBAR
444
445 XtVaSetValues((Widget) m_workArea, XmNheight, height, NULL);
446 }
447 PreResize();
448
449 wxSizeEvent sizeEvent(wxSize(width, height), GetId());
450 sizeEvent.SetEventObject(this);
451
452 GetEventHandler()->ProcessEvent(sizeEvent);
453
454 }
455
456 void wxFrame::GetSize(int *width, int *height) const
457 {
458 Dimension xx, yy;
459 XtVaGetValues((Widget) m_frameShell, XmNwidth, &xx, XmNheight, &yy, NULL);
460 *width = xx; *height = yy;
461 }
462
463 void wxFrame::GetPosition(int *x, int *y) const
464 {
465 Window parent_window = XtWindow((Widget) m_frameShell),
466 next_parent = XtWindow((Widget) m_frameShell),
467 root = RootWindowOfScreen(XtScreen((Widget) m_frameShell));
468
469 // search for the parent that is child of ROOT, because the WM may
470 // reparent twice and notify only the next parent (like FVWM)
471 while (next_parent != root) {
472 Window *theChildren; unsigned int n;
473 parent_window = next_parent;
474 XQueryTree(XtDisplay((Widget) m_frameShell), parent_window, &root,
475 &next_parent, &theChildren, &n);
476 XFree(theChildren); // not needed
477 }
478 int xx, yy; unsigned int dummy;
479 XGetGeometry(XtDisplay((Widget) m_frameShell), parent_window, &root,
480 &xx, &yy, &dummy, &dummy, &dummy, &dummy);
481 if (x) *x = xx;
482 if (y) *y = yy;
483 }
484
485 void wxFrame::DoSetSize(int x, int y, int width, int height, int sizeFlags)
486 {
487 if (x > -1)
488 XtVaSetValues((Widget) m_frameShell, XmNx, x, NULL);
489 if (y > -1)
490 XtVaSetValues((Widget) m_frameShell, XmNy, y, NULL);
491 if (width > -1)
492 XtVaSetValues((Widget) m_frameWidget, XmNwidth, width, NULL);
493 if (height > -1)
494 XtVaSetValues((Widget) m_frameWidget, XmNheight, height, NULL);
495
496 if (!(height == -1 && width == -1))
497 {
498 PreResize();
499
500 wxSizeEvent sizeEvent(wxSize(width, height), GetId());
501 sizeEvent.SetEventObject(this);
502
503 GetEventHandler()->ProcessEvent(sizeEvent);
504 }
505 }
506
507 bool wxFrame::Show(bool show)
508 {
509 if (!m_frameShell)
510 return wxWindow::Show(show);
511
512 m_visibleStatus = show; /* show-&-hide fix */
513
514 m_isShown = show;
515 if (show) {
516 XtMapWidget((Widget) m_frameShell);
517 XRaiseWindow(XtDisplay((Widget) m_frameShell), XtWindow((Widget) m_frameShell));
518 } else {
519 XtUnmapWidget((Widget) m_frameShell);
520 // XmUpdateDisplay(wxTheApp->topLevel); // Experimental: may be responsible for crashes
521 }
522 return TRUE;
523 }
524
525 void wxFrame::Iconize(bool iconize)
526 {
527 if (!iconize)
528 Show(TRUE);
529
530 if (m_frameShell)
531 XtVaSetValues((Widget) m_frameShell, XmNiconic, (Boolean)iconize, NULL);
532 }
533
534 // Equivalent to maximize/restore in Windows
535 void wxFrame::Maximize(bool maximize)
536 {
537 Show(TRUE);
538
539 if (maximize && m_frameShell)
540 XtVaSetValues((Widget) m_frameShell, XmNiconic, FALSE, NULL);
541 }
542
543 bool wxFrame::IsIconized() const
544 {
545 if (!m_frameShell)
546 return FALSE;
547
548 Boolean iconic;
549 XtVaGetValues((Widget) m_frameShell, XmNiconic, &iconic, NULL);
550 return iconic;
551 }
552
553 // Is it maximized?
554 bool wxFrame::IsMaximized(void) const
555 {
556 // No maximizing in Motif (?)
557 return FALSE;
558 }
559
560 void wxFrame::SetTitle(const wxString& title)
561 {
562 if (title == m_title)
563 return;
564
565 m_title = title;
566
567 if (!title.IsNull())
568 XtVaSetValues((Widget) m_frameShell,
569 XmNtitle, (const char*) title,
570 XmNiconName, (const char*) title,
571 NULL);
572 }
573
574 void wxFrame::SetIcon(const wxIcon& icon)
575 {
576 m_icon = icon;
577
578 if (!m_frameShell)
579 return;
580
581 if (!icon.Ok() || !icon.GetPixmap())
582 return;
583
584 XtVaSetValues((Widget) m_frameShell, XtNiconPixmap, icon.GetPixmap(), NULL);
585 }
586
587 wxStatusBar *wxFrame::OnCreateStatusBar(int number, long style, wxWindowID id,
588 const wxString& name)
589 {
590 wxStatusBar *statusBar = NULL;
591
592 statusBar = new wxStatusBar(this, id, wxPoint(0, 0), wxSize(100, 20),
593 style, name);
594
595 // Set the height according to the font and the border size
596 wxClientDC dc(statusBar);
597 dc.SetFont(statusBar->GetFont());
598
599 long x, y;
600 dc.GetTextExtent("X", &x, &y);
601
602 int height = (int)( (y * 1.1) + 2* statusBar->GetBorderY());
603
604 statusBar->SetSize(-1, -1, 100, height);
605
606 statusBar->SetFieldsCount(number);
607 return statusBar;
608 }
609
610 wxStatusBar* wxFrame::CreateStatusBar(int number, long style, wxWindowID id,
611 const wxString& name)
612 {
613 // Calling CreateStatusBar twice is an error.
614 wxCHECK_MSG( m_frameStatusBar == NULL, FALSE,
615 "recreating status bar in wxFrame" );
616
617 m_frameStatusBar = OnCreateStatusBar(number, style, id,
618 name);
619 if ( m_frameStatusBar )
620 {
621 PositionStatusBar();
622 return m_frameStatusBar;
623 }
624 else
625 return NULL;
626 }
627
628 void wxFrame::SetStatusText(const wxString& text, int number)
629 {
630 wxCHECK_RET( m_frameStatusBar != NULL, "no statusbar to set text for" );
631
632 m_frameStatusBar->SetStatusText(text, number);
633 }
634
635 void wxFrame::SetStatusWidths(int n, const int widths_field[])
636 {
637 wxCHECK_RET( m_frameStatusBar != NULL, "no statusbar to set widths for" );
638
639 m_frameStatusBar->SetStatusWidths(n, widths_field);
640 PositionStatusBar();
641 }
642
643 void wxFrame::PositionStatusBar()
644 {
645 if (!m_frameStatusBar)
646 return;
647
648 int w, h;
649 GetClientSize(&w, &h);
650 int sw, sh;
651 m_frameStatusBar->GetSize(&sw, &sh);
652
653 // Since we wish the status bar to be directly under the client area,
654 // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS.
655 m_frameStatusBar->SetSize(0, h, w, sh);
656 }
657
658 WXWidget wxFrame::GetMenuBarWidget() const
659 {
660 if (GetMenuBar())
661 return GetMenuBar()->GetMainWidget();
662 else
663 return (WXWidget) NULL;
664 }
665
666 void wxFrame::SetMenuBar(wxMenuBar *menuBar)
667 {
668 if (!menuBar)
669 {
670 m_frameMenuBar = NULL;
671 return;
672 }
673
674 // Currently can't set it twice
675 // wxASSERT_MSG( (m_frameMenuBar == (wxMenuBar*) NULL), "Cannot set the menubar more than once");
676
677 if (m_frameMenuBar)
678 {
679 m_frameMenuBar->DestroyMenuBar();
680 delete m_frameMenuBar;
681 }
682
683 m_frameMenuBar = menuBar;
684 m_frameMenuBar->CreateMenuBar(this);
685 }
686
687 void wxFrame::Fit()
688 {
689 // Work out max. size
690 wxNode *node = GetChildren().First();
691 int max_width = 0;
692 int max_height = 0;
693 while (node)
694 {
695 // Find a child that's a subwindow, but not a dialog box.
696 wxWindow *win = (wxWindow *)node->Data();
697
698 if (!win->IsKindOf(CLASSINFO(wxFrame)) &&
699 !win->IsKindOf(CLASSINFO(wxDialog)))
700 {
701 int width, height;
702 int x, y;
703 win->GetSize(&width, &height);
704 win->GetPosition(&x, &y);
705
706 if ((x + width) > max_width)
707 max_width = x + width;
708 if ((y + height) > max_height)
709 max_height = y + height;
710 }
711 node = node->Next();
712 }
713 SetClientSize(max_width, max_height);
714 }
715
716 // Responds to colour changes, and passes event on to children.
717 void wxFrame::OnSysColourChanged(wxSysColourChangedEvent& event)
718 {
719 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE));
720 Refresh();
721
722 if ( m_frameStatusBar )
723 {
724 wxSysColourChangedEvent event2;
725 event2.SetEventObject( m_frameStatusBar );
726 m_frameStatusBar->ProcessEvent(event2);
727 }
728
729 // Propagate the event to the non-top-level children
730 wxWindow::OnSysColourChanged(event);
731 }
732
733 // Default resizing behaviour - if only ONE subwindow,
734 // resize to client rectangle size
735 void wxFrame::OnSize(wxSizeEvent& event)
736 {
737 // if we're using constraints - do use them
738 #if wxUSE_CONSTRAINTS
739 if ( GetAutoLayout() ) {
740 Layout();
741 return;
742 }
743 #endif
744
745 // do we have _exactly_ one child?
746 wxWindow *child = NULL;
747 for ( wxNode *node = GetChildren().First(); node; node = node->Next() )
748 {
749 wxWindow *win = (wxWindow *)node->Data();
750 if ( !win->IsKindOf(CLASSINFO(wxFrame)) &&
751 !win->IsKindOf(CLASSINFO(wxDialog)) &&
752 (win != GetStatusBar())
753 #if wxUSE_TOOLBAR
754 && (win != GetToolBar())
755 #endif // wxUSE_TOOLBAR
756 )
757 {
758 if ( child )
759 return; // it's our second subwindow - nothing to do
760 child = win;
761 }
762 }
763
764 if ( child ) {
765 // we have exactly one child - set it's size to fill the whole frame
766 int clientW, clientH;
767 GetClientSize(&clientW, &clientH);
768
769 int x = 0;
770 int y = 0;
771
772 child->SetSize(x, y, clientW, clientH);
773 }
774 }
775
776 // Default activation behaviour - set the focus for the first child
777 // subwindow found.
778 void wxFrame::OnActivate(wxActivateEvent& event)
779 {
780 for(wxNode *node = GetChildren().First(); node; node = node->Next())
781 {
782 // Find a child that's a subwindow, but not a dialog box.
783 wxWindow *child = (wxWindow *)node->Data();
784 if (!child->IsKindOf(CLASSINFO(wxFrame)) &&
785 !child->IsKindOf(CLASSINFO(wxDialog)))
786 {
787 child->SetFocus();
788 return;
789 }
790 }
791 }
792
793 // The default implementation for the close window event.
794 // OnClose for backward compatibility.
795
796 void wxFrame::OnCloseWindow(wxCloseEvent& event)
797 {
798 this->Destroy();
799 }
800
801 // Destroy the window (delayed, if a managed window)
802 bool wxFrame::Destroy()
803 {
804 if (!wxPendingDelete.Member(this))
805 wxPendingDelete.Append(this);
806 return TRUE;
807 }
808
809 // Default menu selection behaviour - display a help string
810 void wxFrame::OnMenuHighlight(wxMenuEvent& event)
811 {
812 if (GetStatusBar())
813 {
814 if (event.GetMenuId() == -1)
815 SetStatusText("");
816 else
817 {
818 wxMenuBar *menuBar = GetMenuBar();
819 if (menuBar)
820 {
821 wxString helpString(menuBar->GetHelpString(event.GetMenuId()));
822 if (helpString != "")
823 SetStatusText(helpString);
824 }
825 }
826 }
827 }
828
829 wxMenuBar *wxFrame::GetMenuBar() const
830 {
831 return m_frameMenuBar;
832 }
833
834 void wxFrame::Centre(int direction)
835 {
836 int display_width, display_height, width, height, x, y;
837 wxDisplaySize(&display_width, &display_height);
838
839 GetSize(&width, &height);
840 GetPosition(&x, &y);
841
842 if (direction & wxHORIZONTAL)
843 x = (int)((display_width - width)/2);
844 if (direction & wxVERTICAL)
845 y = (int)((display_height - height)/2);
846
847 SetSize(x, y, width, height);
848 }
849
850 // Call this to simulate a menu command
851 void wxFrame::Command(int id)
852 {
853 ProcessCommand(id);
854 }
855
856 void wxFrame::ProcessCommand(int id)
857 {
858 wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id);
859 commandEvent.SetInt( id );
860 commandEvent.SetEventObject( this );
861
862 wxMenuBar *bar = GetMenuBar() ;
863 if (!bar)
864 return;
865
866 /* TODO: check the menu item if required
867 wxMenuItem *item = bar->FindItemForId(id) ;
868 if (item && item->IsCheckable())
869 {
870 bar->Check(id,!bar->Checked(id)) ;
871 }
872 */
873
874 wxEvtHandler* evtHandler = GetEventHandler();
875
876 evtHandler->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