1 /////////////////////////////////////////////////////////////////////////////
4 // Author: David Webster
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
25 #include "wx/dialog.h"
26 #include "wx/settings.h"
27 #include "wx/dcclient.h"
30 #include "wx/os2/private.h"
31 #include "wx/statusbr.h"
32 #include "wx/toolbar.h"
33 #include "wx/menuitem.h"
36 extern wxWindowList wxModelessWindows
;
37 extern wxList WXDLLEXPORT wxPendingDelete
;
38 extern wxChar wxFrameClassName
[];
39 extern wxMenu
*wxCurrentPopupMenu
;
41 #if !USE_SHARED_LIBRARY
42 BEGIN_EVENT_TABLE(wxFrame
, wxWindow
)
43 EVT_SIZE(wxFrame::OnSize
)
44 EVT_ACTIVATE(wxFrame::OnActivate
)
45 EVT_MENU_HIGHLIGHT_ALL(wxFrame::OnMenuHighlight
)
46 EVT_SYS_COLOUR_CHANGED(wxFrame::OnSysColourChanged
)
47 EVT_IDLE(wxFrame::OnIdle
)
48 EVT_CLOSE(wxFrame::OnCloseWindow
)
51 IMPLEMENT_DYNAMIC_CLASS(wxFrame
, wxWindow
)
54 bool wxFrame::m_useNativeStatusBar
= FALSE
;
58 m_frameToolBar
= NULL
;
59 m_frameMenuBar
= NULL
;
60 m_frameStatusBar
= NULL
;
65 bool wxFrame::Create(wxWindow
*parent
,
67 const wxString
& title
,
78 m_windowStyle
= style
;
79 m_frameMenuBar
= NULL
;
80 m_frameToolBar
= NULL
;
81 m_frameStatusBar
= NULL
;
83 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
));
89 m_windowId
= (int)NewControlId();
91 if (parent
) parent
->AddChild(this);
100 // we pass NULL as parent to MSWCreate because frames with parents behave
101 // very strangely under Win95 shell
102 // Alteration by JACS: keep normal Windows behaviour (float on top of parent)
104 if ((m_windowStyle
& wxFRAME_FLOAT_ON_PARENT
) == 0)
108 wxTopLevelWindows
.Append(this);
110 OS2Create(m_windowId
, parent
, wxFrameClassName
, this, title
,
111 x
, y
, width
, height
, style
);
113 wxModelessWindows
.Append(this);
119 m_isBeingDeleted
= TRUE
;
120 wxTopLevelWindows
.DeleteObject(this);
122 if (m_frameStatusBar
)
123 delete m_frameStatusBar
;
125 delete m_frameMenuBar
;
127 /* New behaviour March 1998: check if it's the last top-level window */
128 // if (wxTheApp && (this == wxTheApp->GetTopWindow()))
130 if (wxTheApp
&& (wxTopLevelWindows
.Number() == 0))
132 wxTheApp
->SetTopWindow(NULL
);
134 if (wxTheApp
->GetExitOnFrameDelete())
136 // PostQuitMessage(0);
140 wxModelessWindows
.DeleteObject(this);
142 // For some reason, wxWindows can activate another task altogether
143 // when a frame is destroyed after a modal dialog has been invoked.
144 // Try to bring the parent to the top.
145 // MT:Only do this if this frame is currently the active window, else weird
146 // things start to happen
150 if ( wxGetActiveWindow() == this )
151 if (GetParent() && GetParent()->GetHWND())
152 ::BringWindowToTop((HWND) GetParent()->GetHWND());
156 // Get size *available for subwindows* i.e. excluding menu bar, toolbar etc.
157 void wxFrame::DoGetClientSize(int *x
, int *y
) const
162 ::GetClientRect(GetHwnd(), &rect);
164 if ( GetStatusBar() )
166 int statusX, statusY;
167 GetStatusBar()->GetClientSize(&statusX, &statusY);
168 rect.bottom -= statusY;
171 wxPoint pt(GetClientAreaOrigin());
182 // Set the client size (i.e. leave the calculation of borders etc.
184 void wxFrame::DoSetClientSize(int width
, int height
)
186 HWND hWnd
= GetHwnd();
191 ::GetClientRect(hWnd, &rect);
194 GetWindowRect(hWnd, &rect2);
196 // Find the difference between the entire window (title bar and all)
197 // and the client area; add this to the new client size to move the
199 int actual_width = rect2.right - rect2.left - rect.right + width;
200 int actual_height = rect2.bottom - rect2.top - rect.bottom + height;
202 if ( GetStatusBar() )
204 int statusX, statusY;
205 GetStatusBar()->GetClientSize(&statusX, &statusY);
206 actual_height += statusY;
209 wxPoint pt(GetClientAreaOrigin());
210 actual_width += pt.y;
211 actual_height += pt.x;
214 point.x = rect2.left;
217 MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)TRUE);
219 wxSizeEvent event(wxSize(width, height), m_windowId);
220 event.SetEventObject( this );
221 GetEventHandler()->ProcessEvent(event);
225 void wxFrame::DoGetSize(int *width
, int *height
) const
230 GetWindowRect(GetHwnd(), &rect);
231 *width = rect.right - rect.left;
232 *height = rect.bottom - rect.top;
236 void wxFrame::DoGetPosition(int *x
, int *y
) const
241 GetWindowRect(GetHwnd(), &rect);
251 bool wxFrame::Show(bool show
)
263 // Try to highlight the correct window (the parent)
267 hWndParent = (HWND) GetParent()->GetHWND();
269 ::BringWindowToTop(hWndParent);
273 ShowWindow(GetHwnd(), (BOOL)cshow);
276 BringWindowToTop(GetHwnd());
278 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, m_windowId);
279 event.SetEventObject( this );
280 GetEventHandler()->ProcessEvent(event);
287 void wxFrame::Iconize(bool iconize
)
299 ShowWindow(GetHwnd(), (BOOL)cshow);
300 m_iconized = iconize;
304 // Equivalent to maximize/restore in Windows
305 void wxFrame::Maximize(bool maximize
)
315 ShowWindow(GetHwnd(), cshow);
320 bool wxFrame::IsIconized() const
324 ((wxFrame *)this)->m_iconized = (::IsIconic(GetHwnd()) != 0);
331 bool wxFrame::IsMaximized() const
333 // return (::IsZoomed(GetHwnd()) != 0) ;
337 void wxFrame::SetIcon(const wxIcon
& icon
)
343 SendMessage(GetHwnd(), WM_SETICON,
344 (WPARAM)TRUE, (LPARAM)(HICON) m_icon.GetHICON());
349 wxStatusBar
*wxFrame::OnCreateStatusBar(int number
, long style
, wxWindowID id
,
350 const wxString
& name
)
352 wxStatusBar
*statusBar
= NULL
;
354 statusBar
= new wxStatusBar(this, id
, wxPoint(0, 0), wxSize(100, 20),
357 // Set the height according to the font and the border size
358 wxClientDC
dc(statusBar
);
359 dc
.SetFont(statusBar
->GetFont());
362 dc
.GetTextExtent("X", &x
, &y
);
364 int height
= (int)( (y
* 1.1) + 2* statusBar
->GetBorderY());
366 statusBar
->SetSize(-1, -1, 100, height
);
369 statusBar
->SetFieldsCount(number
);
373 wxStatusBar
* wxFrame::CreateStatusBar(int number
, long style
, wxWindowID id
,
374 const wxString
& name
)
376 // VZ: calling CreateStatusBar twice is an error - why anyone would do it?
377 wxCHECK_MSG( m_frameStatusBar
== NULL
, FALSE
,
378 wxT("recreating status bar in wxFrame") );
380 m_frameStatusBar
= OnCreateStatusBar(number
, style
, id
,
382 if ( m_frameStatusBar
)
385 return m_frameStatusBar
;
391 void wxFrame::SetStatusText(const wxString
& text
, int number
)
393 wxCHECK_RET( m_frameStatusBar
!= NULL
, wxT("no statusbar to set text for") );
395 m_frameStatusBar
->SetStatusText(text
, number
);
398 void wxFrame::SetStatusWidths(int n
, const int widths_field
[])
400 wxCHECK_RET( m_frameStatusBar
!= NULL
, wxT("no statusbar to set widths for") );
402 m_frameStatusBar
->SetStatusWidths(n
, widths_field
);
406 void wxFrame::PositionStatusBar()
408 // native status bar positions itself
409 if (m_frameStatusBar
)
412 GetClientSize(&w
, &h
);
414 m_frameStatusBar
->GetSize(&sw
, &sh
);
416 // Since we wish the status bar to be directly under the client area,
417 // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS.
418 m_frameStatusBar
->SetSize(0, h
, w
, sh
);
421 #endif // wxUSE_STATUSBAR
423 void wxFrame::DetachMenuBar()
427 m_frameMenuBar
->Detach();
428 m_frameMenuBar
= NULL
;
432 void wxFrame::SetMenuBar(wxMenuBar
*menu_bar
)
440 wxCHECK_RET( !menu_bar
->GetFrame(), wxT("this menubar is already attached") );
443 delete m_frameMenuBar
;
445 m_hMenu
= menu_bar
->Create();
450 InternalSetMenuBar();
452 m_frameMenuBar
= menu_bar
;
453 menu_bar
->Attach(this);
456 void wxFrame::InternalSetMenuBar()
460 if ( !::SetMenu(GetHwnd(), (HMENU)m_hMenu) )
462 wxLogLastError("SetMenu");
467 // Responds to colour changes, and passes event on to children.
468 void wxFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
470 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
));
473 if ( m_frameStatusBar
)
475 wxSysColourChangedEvent event2
;
476 event2
.SetEventObject( m_frameStatusBar
);
477 m_frameStatusBar
->GetEventHandler()->ProcessEvent(event2
);
480 // Propagate the event to the non-top-level children
481 wxWindow::OnSysColourChanged(event
);
489 bool wxFrame::OS2Create(int id
, wxWindow
*parent
, const wxChar
*wclass
, wxWindow
*wx_win
, const wxChar
*title
,
490 int x
, int y
, int width
, int height
, long style
)
493 m_defaultIcon
= (WXHICON
) (wxSTD_FRAME_ICON
? wxSTD_FRAME_ICON
: wxDEFAULT_FRAME_ICON
);
495 // If child windows aren't properly drawn initially, WS_CLIPCHILDREN
496 // could be the culprit. But without it, you can get a lot of flicker.
501 if ((style & wxCAPTION) == wxCAPTION)
502 msflags = WS_OVERLAPPED;
506 if (style & wxMINIMIZE_BOX)
507 msflags |= WS_MINIMIZEBOX;
508 if (style & wxMAXIMIZE_BOX)
509 msflags |= WS_MAXIMIZEBOX;
510 if (style & wxTHICK_FRAME)
511 msflags |= WS_THICKFRAME;
512 if (style & wxSYSTEM_MENU)
513 msflags |= WS_SYSMENU;
514 if ((style & wxMINIMIZE) || (style & wxICONIZE))
515 msflags |= WS_MINIMIZE;
516 if (style & wxMAXIMIZE)
517 msflags |= WS_MAXIMIZE;
518 if (style & wxCAPTION)
519 msflags |= WS_CAPTION;
520 if (style & wxCLIP_CHILDREN)
521 msflags |= WS_CLIPCHILDREN;
523 // Keep this in wxFrame because it saves recoding this function
526 if (style & wxTINY_CAPTION_VERT)
527 msflags |= IBS_VERTCAPTION;
528 if (style & wxTINY_CAPTION_HORIZ)
529 msflags |= IBS_HORZCAPTION;
531 if (style & wxTINY_CAPTION_VERT)
532 msflags |= WS_CAPTION;
533 if (style & wxTINY_CAPTION_HORIZ)
534 msflags |= WS_CAPTION;
536 if ((style & wxTHICK_FRAME) == 0)
537 msflags |= WS_BORDER;
539 WXDWORD extendedStyle = MakeExtendedStyle(style);
541 #if !defined(__WIN16__) && !defined(__SC__)
542 if (style & wxFRAME_TOOL_WINDOW)
543 extendedStyle |= WS_EX_TOOLWINDOW;
546 if (style & wxSTAY_ON_TOP)
547 extendedStyle |= WS_EX_TOPMOST;
550 if ( !wxWindow::MSWCreate(id, parent, wclass, wx_win, title, x, y, width, height,
551 msflags, NULL, extendedStyle) )
554 // Seems to be necessary if we use WS_POPUP
555 // style instead of WS_OVERLAPPED
556 if (width > -1 && height > -1)
557 ::PostMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED, MAKELPARAM(width, height));
564 // Default resizing behaviour - if only ONE subwindow, resize to client
566 void wxFrame::OnSize(wxSizeEvent
& event
)
568 // if we're using constraints - do use them
569 #if wxUSE_CONSTRAINTS
570 if ( GetAutoLayout() )
577 // do we have _exactly_ one child?
578 wxWindow
*child
= NULL
;
579 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
581 node
= node
->GetNext() )
583 wxWindow
*win
= node
->GetData();
584 if ( !win
->IsTopLevel()
586 && (win
!= GetStatusBar())
587 #endif // wxUSE_STATUSBAR
589 && (win
!= GetToolBar())
590 #endif // wxUSE_TOOLBAR
594 return; // it's our second subwindow - nothing to do
600 // we have exactly one child - set it's size to fill the whole frame
601 int clientW
, clientH
;
602 GetClientSize(&clientW
, &clientH
);
607 child
->SetSize(x
, y
, clientW
, clientH
);
611 // Default activation behaviour - set the focus for the first child
613 void wxFrame::OnActivate(wxActivateEvent
& event
)
615 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
617 node
= node
->GetNext() )
619 // FIXME all this is totally bogus - we need to do the same as wxPanel,
620 // but how to do it without duplicating the code?
623 wxWindow
*child
= node
->GetData();
625 if ( !child
->IsTopLevel()
627 && !wxDynamicCast(child
, wxToolBar
)
628 #endif // wxUSE_TOOLBAR
630 && !wxDynamicCast(child
, wxStatusBar
)
631 #endif // wxUSE_STATUSBAR
640 // The default implementation for the close window event.
641 void wxFrame::OnCloseWindow(wxCloseEvent
& event
)
646 // Destroy the window (delayed, if a managed window)
647 bool wxFrame::Destroy()
649 if (!wxPendingDelete
.Member(this))
650 wxPendingDelete
.Append(this);
654 // Default menu selection behaviour - display a help string
655 void wxFrame::OnMenuHighlight(wxMenuEvent
& event
)
660 int menuId
= event
.GetMenuId();
663 wxMenuBar
*menuBar
= GetMenuBar();
664 if (menuBar
&& menuBar
->FindItem(menuId
))
666 help
= menuBar
->GetHelpString(menuId
);
670 // set status text even if the string is empty - this will at
671 // least remove the string from the item which was previously
677 wxMenuBar
*wxFrame::GetMenuBar() const
679 return m_frameMenuBar
;
682 bool wxFrame::ProcessCommand(int id
)
684 wxMenuBar
*bar
= GetMenuBar() ;
688 wxMenuItem
*item
= bar
->FindItemForId(id
);
690 if ( item
&& item
->IsCheckable() )
692 bar
->Check(id
, !bar
->IsChecked(id
)) ;
695 wxCommandEvent
commandEvent(wxEVT_COMMAND_MENU_SELECTED
, id
);
696 commandEvent
.SetInt( id
);
697 commandEvent
.SetEventObject( this );
699 return GetEventHandler()->ProcessEvent(commandEvent
);
702 // Checks if there is a toolbar, and returns the first free client position
703 wxPoint
wxFrame::GetClientAreaOrigin() const
709 GetToolBar()->GetSize(& w
, & h
);
711 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL
)
723 void wxFrame::DoScreenToClient(int *x
, int *y
) const
725 wxWindow::DoScreenToClient(x
, y
);
727 // We may be faking the client origin.
728 // So a window that's really at (0, 30) may appear
729 // (to wxWin apps) to be at (0, 0).
730 wxPoint
pt(GetClientAreaOrigin());
735 void wxFrame::DoClientToScreen(int *x
, int *y
) const
737 // We may be faking the client origin.
738 // So a window that's really at (0, 30) may appear
739 // (to wxWin apps) to be at (0, 0).
740 wxPoint
pt1(GetClientAreaOrigin());
744 wxWindow::DoClientToScreen(x
, y
);
748 wxToolBar
* wxFrame::CreateToolBar(long style
, wxWindowID id
, const wxString
& name
)
750 wxCHECK_MSG( m_frameToolBar
== NULL
, FALSE
,
751 wxT("recreating toolbar in wxFrame") );
753 wxToolBar
* toolBar
= OnCreateToolBar(style
, id
, name
);
766 wxToolBar
* wxFrame::OnCreateToolBar(long style
, wxWindowID id
, const wxString
& name
)
768 return new wxToolBar(this, id
, wxDefaultPosition
, wxDefaultSize
, style
, name
);
771 void wxFrame::PositionToolBar()
776 ::GetClientRect(GetHwnd(), &rect);
778 if ( GetStatusBar() )
780 int statusX, statusY;
781 GetStatusBar()->GetClientSize(&statusX, &statusY);
782 rect.bottom -= statusY;
788 GetToolBar()->GetSize(& tw, & th);
790 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL)
792 // Use the 'real' MSW position
793 GetToolBar()->SetSize(0, 0, tw, rect.bottom, wxSIZE_NO_ADJUSTMENTS);
797 // Use the 'real' MSW position
798 GetToolBar()->SetSize(0, 0, rect.right, th, wxSIZE_NO_ADJUSTMENTS);
803 #endif // wxUSE_TOOLBAR
805 // propagate our state change to all child frames: this allows us to emulate X
806 // Windows behaviour where child frames float independently of the parent one
807 // on the desktop, but are iconized/restored with it
808 void wxFrame::IconizeChildFrames(bool bIconize
)
810 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
812 node
= node
->GetNext() )
814 wxWindow
*win
= node
->GetData();
816 if ( win
->IsKindOf(CLASSINFO(wxFrame
)) )
818 ((wxFrame
*)win
)->Iconize(bIconize
);
824 // make the window modal (all other windows unresponsive)
825 void wxFrame::MakeModal(bool modal
)
828 wxEnableTopLevelWindows(FALSE
);
829 Enable(TRUE
); // keep this window enabled
832 wxEnableTopLevelWindows(TRUE
);
837 // ===========================================================================
838 // message processing
839 // ===========================================================================
841 // ---------------------------------------------------------------------------
843 // ---------------------------------------------------------------------------
845 bool wxFrame::OS2TranslateMessage(WXMSG
* pMsg
)
847 if ( wxWindow::OS2TranslateMessage(pMsg
) )
850 // try the menu bar accels
851 wxMenuBar
*menuBar
= GetMenuBar();
855 const wxAcceleratorTable
& acceleratorTable
= menuBar
->GetAccelTable();
856 return acceleratorTable
.Translate(this, pMsg
);
859 // ---------------------------------------------------------------------------
860 // our private (non virtual) message handlers
861 // ---------------------------------------------------------------------------
863 bool wxFrame::HandlePaint()
868 if ( GetUpdateRect(GetHwnd(), &rect, FALSE) )
872 HICON hIcon = m_icon.Ok() ? GetHiconOf(m_icon)
873 : (HICON)m_defaultIcon;
875 // Hold a pointer to the dc so long as the OnPaint() message
876 // is being processed
878 HDC hdc = ::BeginPaint(GetHwnd(), &ps);
880 // Erase background before painting or we get white background
881 MSWDefWindowProc(WM_ICONERASEBKGND, (WORD)(LONG)ps.hdc, 0L);
886 ::GetClientRect(GetHwnd(), &rect);
888 // FIXME: why hardcoded?
889 static const int icon_width = 32;
890 static const int icon_height = 32;
892 int icon_x = (int)((rect.right - icon_width)/2);
893 int icon_y = (int)((rect.bottom - icon_height)/2);
895 ::DrawIcon(hdc, icon_x, icon_y, hIcon);
898 ::EndPaint(GetHwnd(), &ps);
904 return wxWindow::HandlePaint();
909 // nothing to paint - processed
916 bool wxFrame::HandleSize(int x
, int y
, WXUINT id
)
918 bool processed
= FALSE
;
925 // only do it it if we were iconized before, otherwise resizing the
926 // parent frame has a curious side effect of bringing it under it's
931 // restore all child frames too
932 IconizeChildFrames(FALSE);
941 // iconize all child frames too
942 IconizeChildFrames(TRUE);
950 // forward WM_SIZE to status bar control
954 wxSizeEvent
event(wxSize(x
, y
), m_windowId
);
955 event
.SetEventObject( this );
956 processed
= GetEventHandler()->ProcessEvent(event
);
962 bool wxFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND control
)
966 // In case it's e.g. a toolbar.
967 wxWindow
*win
= wxFindWinFromHandle(control
);
969 return win
->OS2Command(cmd
, id
);
972 // handle here commands from menus and accelerators
973 if ( cmd
== 0 || cmd
== 1 )
975 if ( wxCurrentPopupMenu
)
977 wxMenu
*popupMenu
= wxCurrentPopupMenu
;
978 wxCurrentPopupMenu
= NULL
;
980 return popupMenu
->OS2Command(cmd
, id
);
983 if ( ProcessCommand(id
) )
992 bool wxFrame::HandleMenuSelect(WXWORD nItem
, WXWORD flags
, WXHMENU hMenu
)
995 if ( flags
== 0xFFFF && hMenu
== 0 )
997 // menu was removed from screen
1002 else if ( !(flags & MF_POPUP) && !(flags & MF_SEPARATOR) )
1009 // don't give hints for separators (doesn't make sense) nor for the
1010 // items opening popup menus (they don't have them anyhow)
1014 wxMenuEvent
event(wxEVT_MENU_HIGHLIGHT
, item
);
1015 event
.SetEventObject( this );
1017 return GetEventHandler()->ProcessEvent(event
);
1020 // ---------------------------------------------------------------------------
1021 // the window proc for wxFrame
1022 // ---------------------------------------------------------------------------
1024 MRESULT
wxFrame::OS2WindowProc(HWND hwnd
, WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
)
1027 bool processed
= FALSE
;
1034 // if we can't close, tell the system that we processed the
1035 // message - otherwise it would close us
1036 processed = !Close();
1043 UnpackCommand((WXWPARAM)wParam, (WXLPARAM)lParam,
1046 processed = HandleCommand(id, cmd, (WXHWND)hwnd);
1054 UnpackMenuSelect(wParam, lParam, &item, &flags, &hmenu);
1056 processed = HandleMenuSelect(item, flags, hmenu);
1061 processed = HandlePaint();
1064 case WM_QUERYDRAGICON:
1066 HICON hIcon = m_icon.Ok() ? GetHiconOf(m_icon)
1067 : (HICON)(m_defaultIcon);
1069 processed = rc != 0;
1074 processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam);
1079 rc
= wxWindow::OS2WindowProc(hwnd
, message
, wParam
, lParam
);