diff --git a/include/wx/generic/panelg.h b/include/wx/generic/panelg.h index 308be49ecb..de9db536e2 100644 --- a/include/wx/generic/panelg.h +++ b/include/wx/generic/panelg.h @@ -92,6 +92,9 @@ protected: // common part of all ctors void Init(); + // set the focus to the child which had it the last time + bool SetFocusToChild(); + // the child which had the focus last time this panel was activated wxWindow *m_winLastFocused; diff --git a/include/wx/msw/window.h b/include/wx/msw/window.h index e0181bd29b..fd873efbde 100644 --- a/include/wx/msw/window.h +++ b/include/wx/msw/window.h @@ -179,6 +179,8 @@ public: // event handlers // -------------- + + void OnSetFocus(wxFocusEvent& event); void OnEraseBackground(wxEraseEvent& event); void OnIdle(wxIdleEvent& event); diff --git a/src/common/log.cpp b/src/common/log.cpp index 129b253054..2179500499 100644 --- a/src/common/log.cpp +++ b/src/common/log.cpp @@ -178,9 +178,23 @@ void wxLogVerbose(const wxChar *szFormat, ...) if ( pLog != NULL && wxLog::IsAllowedTraceMask(mask) ) { wxCRIT_SECT_LOCKER(locker, gs_csLogBuf); + wxChar *p = s_szBuf; + size_t len = WXSIZEOF(s_szBuf); + strncpy(s_szBuf, _T("Trace ("), len); + len -= 7; // strlen("Trace (") + p += 7; + strncat(p, mask, len); + size_t lenMask = wxStrlen(mask); + len -= lenMask; + p += lenMask; + + strncat(p, _T("): "), len); + len -= 3; + p += 3; + va_list argptr; va_start(argptr, szFormat); - wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr); + wxVsnprintf(p, len, szFormat, argptr); va_end(argptr); wxLog::OnLog(wxLOG_Trace, s_szBuf, time(NULL)); diff --git a/src/generic/panelg.cpp b/src/generic/panelg.cpp index e2b2c838e7..3ff8c2dbc0 100644 --- a/src/generic/panelg.cpp +++ b/src/generic/panelg.cpp @@ -186,59 +186,83 @@ void wxPanel::OnSize(wxSizeEvent& WXUNUSED(event)) void wxPanel::SetFocus() { + wxLogTrace(_T("focus"), _T("SetFocus on wxPanel 0x%08x."), GetHandle()); + // If the panel gets the focus *by way of getting it set directly* // we move the focus to the first window that can get it. - wxNode *node = GetChildren().First(); - while (node) + // VZ: no, we set the focus to the last window too. I don't understand why + // should we make this distinction: if an app wants to set focus to + // some precise control, it may always do it directly, but if we don't + // use m_winLastFocused here, the focus won't be set correctly after a + // notebook page change nor after frame activation under MSW (it calls + // SetFocus too) + // + // If you still want to have old behaviour for wxGTK, edit the + // following line +#if 0 // def __WXGTK__ + m_winLastFocused = (wxWindow *)NULL; +#endif // 0 + + if ( !SetFocusToChild() ) { - wxWindow *child = (wxWindow*) node->Data(); - if (child->AcceptsFocus()) - { - m_winLastFocused = child; // should be redundant, but it is not - child->SetFocus(); - return; - } - node = node->Next(); + wxWindow::SetFocus(); } - - m_winLastFocused = (wxWindow*) NULL; - - wxWindow::SetFocus(); } void wxPanel::OnFocus(wxFocusEvent& event) { + wxLogTrace(_T("focus"), _T("OnFocus on wxPanel 0x%08x."), GetHandle()); + // If the panel gets the focus *by way of getting clicked on* // we move the focus to either the last window that had the // focus or the first one that can get it. - - if (m_winLastFocused) - { - // It might happen that the window got reparented or no longer - // accepts the focus. - if ((m_winLastFocused->GetParent() == this) && - (m_winLastFocused->AcceptsFocus())) - { - m_winLastFocused->SetFocus(); - return; - } - } - - wxNode *node = GetChildren().First(); - while (node) - { - wxWindow *child = (wxWindow*) node->Data(); - if (child->AcceptsFocus()) - { - m_winLastFocused = child; // should be redundant, but it is not - child->SetFocus(); - return; - } - node = node->Next(); - } - - m_winLastFocused = (wxWindow*) NULL; + (void)SetFocusToChild(); event.Skip(); } + +bool wxPanel::SetFocusToChild() +{ + if ( m_winLastFocused ) + { + // It might happen that the window got reparented or no longer accepts + // the focus. + if ( (m_winLastFocused->GetParent() == this) && + m_winLastFocused->AcceptsFocus() ) + { + wxLogTrace(_T("focus"), + _T("SetFocusToChild() => last child (0x%08x)."), + m_winLastFocused->GetHandle()); + + m_winLastFocused->SetFocus(); + return TRUE; + } + else + { + // it doesn't count as such any more + m_winLastFocused = (wxWindow *)NULL; + } + } + + // set the focus to the first child who wants it + wxWindowList::Node *node = GetChildren().GetFirst(); + while ( node ) + { + wxWindow *child = node->GetData(); + if ( child->AcceptsFocus() ) + { + wxLogTrace(_T("focus"), + _T("SetFocusToChild() => first child (0x%08x)."), + child->GetHandle()); + + m_winLastFocused = child; // should be redundant, but it is not + child->SetFocus(); + return TRUE; + } + + node = node->GetNext(); + } + + return FALSE; +} diff --git a/src/msw/frame.cpp b/src/msw/frame.cpp index 704d53784a..1b2f3db2e9 100644 --- a/src/msw/frame.cpp +++ b/src/msw/frame.cpp @@ -559,6 +559,15 @@ bool wxFrame::MSWCreate(int id, wxWindow *parent, const wxChar *wclass, wxWindow // subwindow found. void wxFrame::OnActivate(wxActivateEvent& event) { + if ( !event.GetActive() ) + { + event.Skip(); + + return; + } + + wxLogTrace(_T("focus"), _T("wxFrame %08x activated."), m_hWnd); + for ( wxWindowList::Node *node = GetChildren().GetFirst(); node; node = node->GetNext() ) @@ -579,7 +588,7 @@ void wxFrame::OnActivate(wxActivateEvent& event) ) { child->SetFocus(); - return; + break; } } } diff --git a/src/msw/window.cpp b/src/msw/window.cpp index ec39a8be1d..44c98ddf78 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -141,13 +141,14 @@ wxWindow *wxFindWinFromHandle(WXHWND hWnd); // event tables // --------------------------------------------------------------------------- - IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) +IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase) BEGIN_EVENT_TABLE(wxWindow, wxWindowBase) EVT_ERASE_BACKGROUND(wxWindow::OnEraseBackground) EVT_SYS_COLOUR_CHANGED(wxWindow::OnSysColourChanged) EVT_INIT_DIALOG(wxWindow::OnInitDialog) EVT_IDLE(wxWindow::OnIdle) + EVT_SET_FOCUS(wxWindow::OnSetFocus) END_EVENT_TABLE() // =========================================================================== @@ -2519,6 +2520,33 @@ bool wxWindow::HandleDestroy() // activation/focus // --------------------------------------------------------------------------- +void wxWindow::OnSetFocus(wxFocusEvent& event) +{ + // panel wants to track the window which was the last to have focus in it, + // so we want to set ourselves as the window which last had focus + // + // notice that it's also important to do it upwards the tree becaus + // otherwise when the top level panel gets focus, it won't set it back to + // us, but to some other sibling + wxWindow *win = this; + while ( win ) + { + wxWindow *parent = win->GetParent(); + wxPanel *panel = wxDynamicCast(parent, wxPanel); + if ( panel ) + { + panel->SetLastFocus(win); + } + + win = parent; + } + + wxLogTrace(_T("focus"), _T("%s (0x%08x) gets focus"), + GetClassInfo()->GetClassName(), GetHandle()); + + event.Skip(); +} + bool wxWindow::HandleActivate(int state, bool WXUNUSED(minimized), WXHWND WXUNUSED(activate)) @@ -2541,13 +2569,6 @@ bool wxWindow::HandleSetFocus(WXHWND WXUNUSED(hwnd)) } #endif // wxUSE_CARET - // panel wants to track the window which was the last to have focus in it - wxPanel *panel = wxDynamicCast(GetParent(), wxPanel); - if ( panel ) - { - panel->SetLastFocus(this); - } - wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId); event.SetEventObject(this);