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