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