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