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"
21 #include "wx/dialog.h"
22 #include "wx/settings.h"
23 #include "wx/dcclient.h"
26 #include "wx/os2/private.h"
29 #include "wx/statusbr.h"
30 #endif // wxUSE_STATUSBAR
33 #include "wx/toolbar.h"
34 #endif // wxUSE_TOOLBAR
36 #include "wx/menuitem.h"
39 // ----------------------------------------------------------------------------
41 // ----------------------------------------------------------------------------
43 extern wxWindowList wxModelessWindows
;
44 extern wxList WXDLLEXPORT wxPendingDelete
;
45 extern wxChar wxFrameClassName
[];
46 extern wxMenu
*wxCurrentPopupMenu
;
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 #if !USE_SHARED_LIBRARY
53 BEGIN_EVENT_TABLE(wxFrame
, wxFrameBase
)
54 EVT_ACTIVATE(wxFrame::OnActivate
)
55 EVT_SYS_COLOUR_CHANGED(wxFrame::OnSysColourChanged
)
58 IMPLEMENT_DYNAMIC_CLASS(wxFrame
, wxWindow
)
61 // ============================================================================
63 // ============================================================================
65 // ----------------------------------------------------------------------------
66 // static class members
67 // ----------------------------------------------------------------------------
69 #if wxUSE_NATIVE_STATUSBAR
70 bool wxFrame::m_useNativeStatusBar
= TRUE
;
72 bool wxFrame::m_useNativeStatusBar
= FALSE
;
75 // ----------------------------------------------------------------------------
76 // creation/destruction
77 // ----------------------------------------------------------------------------
88 bool wxFrame::Create(wxWindow
*parent
,
90 const wxString
& title
,
97 m_windowStyle
= style
;
98 m_frameMenuBar
= NULL
;
99 m_frameToolBar
= NULL
;
100 m_frameStatusBar
= NULL
;
102 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE
));
107 m_windowId
= (int)NewControlId();
109 if (parent
) parent
->AddChild(this);
118 // we pass NULL as parent to MSWCreate because frames with parents behave
119 // very strangely under Win95 shell
120 // Alteration by JACS: keep normal Windows behaviour (float on top of parent)
122 if ((m_windowStyle
& wxFRAME_FLOAT_ON_PARENT
) == 0)
126 wxTopLevelWindows
.Append(this);
128 OS2Create(m_windowId
, parent
, wxFrameClassName
, this, title
,
129 x
, y
, width
, height
, style
);
131 wxModelessWindows
.Append(this);
137 m_isBeingDeleted
= TRUE
;
138 wxTopLevelWindows
.DeleteObject(this);
144 if (wxTheApp && (wxTopLevelWindows.Number() == 0))
146 wxTheApp->SetTopWindow(NULL);
148 if (wxTheApp->GetExitOnFrameDelete())
154 wxModelessWindows.DeleteObject(this);
156 // For some reason, wxWindows can activate another task altogether
157 // when a frame is destroyed after a modal dialog has been invoked.
158 // Try to bring the parent to the top.
159 // MT:Only do this if this frame is currently the active window, else weird
160 // things start to happen
161 if ( wxGetActiveWindow() == this )
162 if (GetParent() && GetParent()->GetHWND())
163 ::BringWindowToTop((HWND) GetParent()->GetHWND());
167 // Get size *available for subwindows* i.e. excluding menu bar, toolbar etc.
168 void wxFrame::DoGetClientSize(int *x
, int *y
) const
173 ::GetClientRect(GetHwnd(), &rect);
176 if ( GetStatusBar() )
178 int statusX, statusY;
179 GetStatusBar()->GetClientSize(&statusX, &statusY);
180 rect.bottom -= statusY;
182 #endif // wxUSE_STATUSBAR
184 wxPoint pt(GetClientAreaOrigin());
195 // Set the client size (i.e. leave the calculation of borders etc.
197 void wxFrame::DoSetClientSize(int width
, int height
)
199 HWND hWnd
= GetHwnd();
204 ::GetClientRect(hWnd, &rect);
207 GetWindowRect(hWnd, &rect2);
209 // Find the difference between the entire window (title bar and all)
210 // and the client area; add this to the new client size to move the
212 int actual_width = rect2.right - rect2.left - rect.right + width;
213 int actual_height = rect2.bottom - rect2.top - rect.bottom + height;
216 if ( GetStatusBar() )
218 int statusX, statusY;
219 GetStatusBar()->GetClientSize(&statusX, &statusY);
220 actual_height += statusY;
222 #endif // wxUSE_STATUSBAR
224 wxPoint pt(GetClientAreaOrigin());
225 actual_width += pt.y;
226 actual_height += pt.x;
229 point.x = rect2.left;
232 MoveWindow(hWnd, point.x, point.y, actual_width, actual_height, (BOOL)TRUE);
234 wxSizeEvent event(wxSize(width, height), m_windowId);
235 event.SetEventObject( this );
236 GetEventHandler()->ProcessEvent(event);
240 void wxFrame::DoGetSize(int *width
, int *height
) const
245 GetWindowRect(GetHwnd(), &rect);
246 *width = rect.right - rect.left;
247 *height = rect.bottom - rect.top;
251 void wxFrame::DoGetPosition(int *x
, int *y
) const
256 GetWindowRect(GetHwnd(), &rect);
266 // ----------------------------------------------------------------------------
267 // variations around ::ShowWindow()
268 // ----------------------------------------------------------------------------
270 void wxFrame::DoShowWindow(int nShowCmd
)
274 ::ShowWindow(GetHwnd(), nShowCmd);
276 m_iconized = nShowCmd == SW_MINIMIZE;
280 bool wxFrame::Show(bool show
)
284 DoShowWindow(show ? SW_SHOW : SW_HIDE);
288 ::BringWindowToTop(GetHwnd());
290 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, m_windowId);
291 event.SetEventObject( this );
292 GetEventHandler()->ProcessEvent(event);
296 // Try to highlight the correct window (the parent)
299 HWND hWndParent = GetHwndOf(GetParent());
301 ::BringWindowToTop(hWndParent);
308 void wxFrame::Iconize(bool iconize
)
310 // DoShowWindow(iconize ? SW_MINIMIZE : SW_RESTORE);
313 void wxFrame::Maximize(bool maximize
)
315 // DoShowWindow(maximize ? SW_MAXIMIZE : SW_RESTORE);
318 void wxFrame::Restore()
320 // DoShowWindow(SW_RESTORE);
323 bool wxFrame::IsIconized() const
327 ((wxFrame *)this)->m_iconized = (::IsIconic(GetHwnd()) != 0);
334 bool wxFrame::IsMaximized() const
338 return (::IsZoomed(GetHwnd()) != 0);
343 void wxFrame::SetIcon(const wxIcon
& icon
)
345 wxFrameBase::SetIcon(icon
);
351 SendMessage(GetHwnd(), WM_SETICON,
352 (WPARAM)TRUE, (LPARAM)(HICON) m_icon.GetHICON());
358 wxStatusBar
*wxFrame::OnCreateStatusBar(int number
,
361 const wxString
& name
)
363 wxStatusBar
*statusBar
= NULL
;
365 statusBar
= wxFrameBase::OnCreateStatusBar(number
, style
, id
, name
);
370 void wxFrame::PositionStatusBar()
374 // native status bar positions itself
375 if ( m_frameStatusBar )
378 GetClientSize(&w, &h);
380 m_frameStatusBar->GetSize(&sw, &sh);
382 // Since we wish the status bar to be directly under the client area,
383 // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS.
384 m_frameStatusBar->SetSize(0, h, w, sh);
388 #endif // wxUSE_STATUSBAR
390 void wxFrame::DetachMenuBar()
394 m_frameMenuBar
->Detach();
395 m_frameMenuBar
= NULL
;
399 void wxFrame::SetMenuBar(wxMenuBar
*menu_bar
)
407 wxCHECK_RET( !menu_bar
->GetFrame(), wxT("this menubar is already attached") );
410 delete m_frameMenuBar
;
412 m_hMenu
= menu_bar
->Create();
417 InternalSetMenuBar();
419 m_frameMenuBar
= menu_bar
;
420 menu_bar
->Attach(this);
423 void wxFrame::InternalSetMenuBar()
427 if ( !::SetMenu(GetHwnd(), (HMENU)m_hMenu) )
429 wxLogLastError("SetMenu");
434 // Responds to colour changes, and passes event on to children.
435 void wxFrame::OnSysColourChanged(wxSysColourChangedEvent
& event
)
439 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE));
442 if ( m_frameStatusBar )
444 wxSysColourChangedEvent event2;
445 event2.SetEventObject( m_frameStatusBar );
446 m_frameStatusBar->GetEventHandler()->ProcessEvent(event2);
449 // Propagate the event to the non-top-level children
450 wxWindow::OnSysColourChanged(event);
459 bool wxFrame::OS2Create(int id
, wxWindow
*parent
, const wxChar
*wclass
, wxWindow
*wx_win
, const wxChar
*title
,
460 int x
, int y
, int width
, int height
, long style
)
463 m_defaultIcon
= (WXHICON
) (wxSTD_FRAME_ICON
? wxSTD_FRAME_ICON
: wxDEFAULT_FRAME_ICON
);
465 // If child windows aren't properly drawn initially, WS_CLIPCHILDREN
466 // could be the culprit. But without it, you can get a lot of flicker.
471 if ((style & wxCAPTION) == wxCAPTION)
472 msflags = WS_OVERLAPPED;
476 if (style & wxMINIMIZE_BOX)
477 msflags |= WS_MINIMIZEBOX;
478 if (style & wxMAXIMIZE_BOX)
479 msflags |= WS_MAXIMIZEBOX;
480 if (style & wxTHICK_FRAME)
481 msflags |= WS_THICKFRAME;
482 if (style & wxSYSTEM_MENU)
483 msflags |= WS_SYSMENU;
484 if ((style & wxMINIMIZE) || (style & wxICONIZE))
485 msflags |= WS_MINIMIZE;
486 if (style & wxMAXIMIZE)
487 msflags |= WS_MAXIMIZE;
488 if (style & wxCAPTION)
489 msflags |= WS_CAPTION;
490 if (style & wxCLIP_CHILDREN)
491 msflags |= WS_CLIPCHILDREN;
493 // Keep this in wxFrame because it saves recoding this function
496 if (style & wxTINY_CAPTION_VERT)
497 msflags |= IBS_VERTCAPTION;
498 if (style & wxTINY_CAPTION_HORIZ)
499 msflags |= IBS_HORZCAPTION;
501 if (style & wxTINY_CAPTION_VERT)
502 msflags |= WS_CAPTION;
503 if (style & wxTINY_CAPTION_HORIZ)
504 msflags |= WS_CAPTION;
506 if ((style & wxTHICK_FRAME) == 0)
507 msflags |= WS_BORDER;
509 WXDWORD extendedStyle = MakeExtendedStyle(style);
511 #if !defined(__WIN16__) && !defined(__SC__)
512 if (style & wxFRAME_TOOL_WINDOW)
513 extendedStyle |= WS_EX_TOOLWINDOW;
516 if (style & wxSTAY_ON_TOP)
517 extendedStyle |= WS_EX_TOPMOST;
520 if ( !wxWindow::MSWCreate(id, parent, wclass, wx_win, title, x, y, width, height,
521 msflags, NULL, extendedStyle) )
524 // Seems to be necessary if we use WS_POPUP
525 // style instead of WS_OVERLAPPED
526 if (width > -1 && height > -1)
527 ::PostMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED, MAKELPARAM(width, height));
532 // Default activation behaviour - set the focus for the first child
534 void wxFrame::OnActivate(wxActivateEvent
& event
)
536 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
538 node
= node
->GetNext() )
540 // FIXME all this is totally bogus - we need to do the same as wxPanel,
541 // but how to do it without duplicating the code?
544 wxWindow
*child
= node
->GetData();
546 if ( !child
->IsTopLevel()
548 && !wxDynamicCast(child
, wxToolBar
)
549 #endif // wxUSE_TOOLBAR
551 && !wxDynamicCast(child
, wxStatusBar
)
552 #endif // wxUSE_STATUSBAR
561 // ----------------------------------------------------------------------------
562 // wxFrame size management: we exclude the areas taken by menu/status/toolbars
563 // from the client area, so the client area is what's really available for the
565 // ----------------------------------------------------------------------------
567 // Checks if there is a toolbar, and returns the first free client position
568 wxPoint
wxFrame::GetClientAreaOrigin() const
574 GetToolBar()->GetSize(& w
, & h
);
576 if (GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL
)
588 void wxFrame::DoScreenToClient(int *x
, int *y
) const
590 wxWindow::DoScreenToClient(x
, y
);
592 // We may be faking the client origin.
593 // So a window that's really at (0, 30) may appear
594 // (to wxWin apps) to be at (0, 0).
595 wxPoint
pt(GetClientAreaOrigin());
600 void wxFrame::DoClientToScreen(int *x
, int *y
) const
602 // We may be faking the client origin.
603 // So a window that's really at (0, 30) may appear
604 // (to wxWin apps) to be at (0, 0).
605 wxPoint
pt1(GetClientAreaOrigin());
609 wxWindow::DoClientToScreen(x
, y
);
612 // ----------------------------------------------------------------------------
613 // tool/status bar stuff
614 // ----------------------------------------------------------------------------
618 wxToolBar
* wxFrame::CreateToolBar(long style
, wxWindowID id
, const wxString
& name
)
620 if ( wxFrameBase::CreateToolBar(style
, id
, name
) )
625 return m_frameToolBar
;
628 void wxFrame::PositionToolBar()
633 ::GetClientRect(GetHwnd(), &rect);
636 if ( GetStatusBar() )
638 int statusX, statusY;
639 GetStatusBar()->GetClientSize(&statusX, &statusY);
640 rect.bottom -= statusY;
642 #endif // wxUSE_STATUSBAR
647 GetToolBar()->GetSize(&tw, &th);
649 if ( GetToolBar()->GetWindowStyleFlag() & wxTB_VERTICAL )
658 // Use the 'real' MSW position here
659 GetToolBar()->SetSize(0, 0, tw, th, wxSIZE_NO_ADJUSTMENTS);
663 #endif // wxUSE_TOOLBAR
665 // ----------------------------------------------------------------------------
666 // frame state (iconized/maximized/...)
667 // ----------------------------------------------------------------------------
669 // propagate our state change to all child frames: this allows us to emulate X
670 // Windows behaviour where child frames float independently of the parent one
671 // on the desktop, but are iconized/restored with it
672 void wxFrame::IconizeChildFrames(bool bIconize
)
674 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
676 node
= node
->GetNext() )
678 wxWindow
*win
= node
->GetData();
680 if ( win
->IsKindOf(CLASSINFO(wxFrame
)) )
682 ((wxFrame
*)win
)->Iconize(bIconize
);
687 // ===========================================================================
688 // message processing
689 // ===========================================================================
691 // ---------------------------------------------------------------------------
693 // ---------------------------------------------------------------------------
695 bool wxFrame::OS2TranslateMessage(WXMSG
* pMsg
)
699 if ( wxWindow::OS2TranslateMessage(pMsg) )
702 // try the menu bar accels
703 wxMenuBar
*menuBar
= GetMenuBar();
707 const wxAcceleratorTable
& acceleratorTable
= menuBar
->GetAccelTable();
708 return acceleratorTable
.Translate(this, pMsg
);
711 // ---------------------------------------------------------------------------
712 // our private (non virtual) message handlers
713 // ---------------------------------------------------------------------------
715 bool wxFrame::HandlePaint()
720 if ( GetUpdateRect(GetHwnd(), &rect, FALSE) )
724 HICON hIcon = m_icon.Ok() ? GetHiconOf(m_icon)
725 : (HICON)m_defaultIcon;
727 // Hold a pointer to the dc so long as the OnPaint() message
728 // is being processed
730 HDC hdc = ::BeginPaint(GetHwnd(), &ps);
732 // Erase background before painting or we get white background
733 MSWDefWindowProc(WM_ICONERASEBKGND, (WORD)(LONG)ps.hdc, 0L);
738 ::GetClientRect(GetHwnd(), &rect);
740 // FIXME: why hardcoded?
741 static const int icon_width = 32;
742 static const int icon_height = 32;
744 int icon_x = (int)((rect.right - icon_width)/2);
745 int icon_y = (int)((rect.bottom - icon_height)/2);
747 ::DrawIcon(hdc, icon_x, icon_y, hIcon);
750 ::EndPaint(GetHwnd(), &ps);
756 return wxWindow::HandlePaint();
761 // nothing to paint - processed
768 bool wxFrame::HandleSize(int x
, int y
, WXUINT id
)
770 bool processed
= FALSE
;
777 // only do it it if we were iconized before, otherwise resizing the
778 // parent frame has a curious side effect of bringing it under it's
783 // restore all child frames too
784 IconizeChildFrames(FALSE);
793 // iconize all child frames too
794 IconizeChildFrames(TRUE);
802 // forward WM_SIZE to status bar control
803 #if wxUSE_NATIVE_STATUSBAR
804 if (m_frameStatusBar && m_frameStatusBar->IsKindOf(CLASSINFO(wxStatusBar95)))
806 wxSizeEvent event(wxSize(x, y), m_frameStatusBar->GetId());
807 event.SetEventObject( m_frameStatusBar );
809 ((wxStatusBar95 *)m_frameStatusBar)->OnSize(event);
811 #endif // wxUSE_NATIVE_STATUSBAR
816 wxSizeEvent event(wxSize(x, y), m_windowId);
817 event.SetEventObject( this );
818 processed = GetEventHandler()->ProcessEvent(event);
824 bool wxFrame::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND control
)
830 // In case it's e.g. a toolbar.
831 wxWindow *win = wxFindWinFromHandle(control);
833 return win->MSWCommand(cmd, id);
836 // handle here commands from menus and accelerators
837 if ( cmd == 0 || cmd == 1 )
839 if ( wxCurrentPopupMenu )
841 wxMenu *popupMenu = wxCurrentPopupMenu;
842 wxCurrentPopupMenu = NULL;
844 return popupMenu->MSWCommand(cmd, id);
847 if ( ProcessCommand(id) )
856 bool wxFrame::HandleMenuSelect(WXWORD nItem
, WXWORD flags
, WXHMENU hMenu
)
859 if ( flags
== 0xFFFF && hMenu
== 0 )
861 // menu was removed from screen
866 else if ( !(flags & MF_POPUP) && !(flags & MF_SEPARATOR) )
872 // don't give hints for separators (doesn't make sense) nor for the
873 // items opening popup menus (they don't have them anyhow)
877 wxMenuEvent
event(wxEVT_MENU_HIGHLIGHT
, item
);
878 event
.SetEventObject( this );
880 return GetEventHandler()->ProcessEvent(event
);
883 // ---------------------------------------------------------------------------
884 // the window proc for wxFrame
885 // ---------------------------------------------------------------------------
887 MRESULT
wxFrame::OS2WindowProc(HWND hwnd
, WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
)
890 bool processed
= FALSE
;
897 // if we can't close, tell the system that we processed the
898 // message - otherwise it would close us
899 processed = !Close();
906 UnpackCommand((WXWPARAM)wParam, (WXLPARAM)lParam,
909 processed = HandleCommand(id, cmd, (WXHWND)hwnd);
917 UnpackMenuSelect(wParam, lParam, &item, &flags, &hmenu);
919 processed = HandleMenuSelect(item, flags, hmenu);
924 processed = HandlePaint();
927 case WM_QUERYDRAGICON:
929 HICON hIcon = m_icon.Ok() ? GetHiconOf(m_icon)
930 : (HICON)(m_defaultIcon);
937 processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam);
942 rc = wxWindow::MSWWindowProc(message, wParam, lParam);