From fd2be5df8d8a250c7987631e996f49ab024a4b54 Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= Date: Thu, 28 Jun 2007 12:57:17 +0000 Subject: [PATCH] fixes to handling of focus changes for toplevel windows git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@46998 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- src/dfb/nonownedwnd.cpp | 74 +++++++++++++++++++++++++++++++++++++++-- src/dfb/toplevel.cpp | 2 ++ src/dfb/window.cpp | 3 +- 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/src/dfb/nonownedwnd.cpp b/src/dfb/nonownedwnd.cpp index 35e8d3fd74..58d59ebebc 100644 --- a/src/dfb/nonownedwnd.cpp +++ b/src/dfb/nonownedwnd.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// // Name: src/dfb/nonownedwnd.cpp -// Purpose: implementation of wxNonOwnedWindowow +// Purpose: implementation of wxNonOwnedWindow // Author: Vaclav Slavik // Created: 2006-12-24 // RCS-ID: $Id$ @@ -243,7 +243,18 @@ bool wxNonOwnedWindow::Show(bool show) m_dfbwin->SetOpacity(show ? m_opacity : 0); if ( show ) - SetDfbFocus(); + { + wxWindow *focused = FindFocus(); + if ( focused && focused->GetTLW() == this ) + { + // focus is on this frame or its children, apply it to DirectFB + SetDfbFocus(); + } + // else: don't do anything, if this is wxFrame or wxDialog that should + // get focus when it's shown, + // wxTopLevelWindowDFB::HandleFocusEvent() will do it as soon as + // the event loop starts + } return true; } @@ -368,12 +379,66 @@ void wxNonOwnedWindow::Update() // events handling // --------------------------------------------------------------------------- +namespace +{ + +static wxNonOwnedWindow *gs_insideDFBFocusHandlerOf = NULL; + +struct InsideDFBFocusHandlerSetter +{ + InsideDFBFocusHandlerSetter(wxNonOwnedWindow *win) + { + wxASSERT( gs_insideDFBFocusHandlerOf == NULL ); + gs_insideDFBFocusHandlerOf = win; + } + ~InsideDFBFocusHandlerSetter() + { + gs_insideDFBFocusHandlerOf = NULL; + } +}; + +} // anonymous namespace + + void wxNonOwnedWindow::SetDfbFocus() { wxCHECK_RET( IsShown(), _T("cannot set focus to hidden window") ); wxASSERT_MSG( FindFocus() && FindFocus()->GetTLW() == this, _T("setting DirectFB focus to unexpected window") ); + // Don't set DirectFB focus if we're called from HandleFocusEvent() on + // this window, because we already have the focus in that case. Not only + // would it be unnecessary, it would be harmful: RequestFocus() adds + // an event to DirectFB event queue and calling it when in + // HandleFocusEvent() could result in a window being focused when it + // should not be. Consider this example: + // + // tlw1->SetFocus(); // (1) + // tlw2->SetFocus(); // (2) + // + // This results in adding these events to DFB queue: + // + // DWET_GOTFOCUS(tlw1) + // DWET_LOSTFOCUS(tlw1) + // DWET_GOTFOCUS(tlw2) + // + // Note that the events are processed by event loop, i.e. not between + // execution of lines (1) and (2) above. So by the time the first + // DWET_GOTFOCUS event is handled, tlw2->SetFocus() was already executed. + // If we onconditionally called RequestFocus() from here, handling the + // first event would result in this change to the event queue: + // + // DWET_LOSTFOCUS(tlw1) + // DWET_GOTFOCUS(tlw2) // (3) + // DWET_LOSTFOCUS(tlw2) + // DWET_GOTFOCUS(tlw1) + // + // And the focus would get back to tlw1 even though that's not what we + // wanted. + + if ( gs_insideDFBFocusHandlerOf == this ) + return; + GetDirectFBWindow()->RequestFocus(); } @@ -413,7 +478,10 @@ void wxNonOwnedWindow::HandleDFBWindowEvent(const wxDFBWindowEvent& event_) case DWET_GOTFOCUS: case DWET_LOSTFOCUS: - tlw->HandleFocusEvent(event_); + { + InsideDFBFocusHandlerSetter inside(tlw); + tlw->HandleFocusEvent(event_); + } break; case DWET_NONE: diff --git a/src/dfb/toplevel.cpp b/src/dfb/toplevel.cpp index c8c36de1f1..cb557cc2c3 100644 --- a/src/dfb/toplevel.cpp +++ b/src/dfb/toplevel.cpp @@ -200,6 +200,8 @@ void wxTopLevelWindowDFB::HandleFocusEvent(const wxDFBWindowEvent& event_) if ( CanAcceptFocus() ) SetFocus(); + else + wxLogTrace(TRACE_EVENTS, "...which doesn't accept it"); } } } diff --git a/src/dfb/window.cpp b/src/dfb/window.cpp index b3f8121c5e..f82ffb8ed6 100644 --- a/src/dfb/window.cpp +++ b/src/dfb/window.cpp @@ -194,7 +194,8 @@ void wxWindowDFB::SetFocus() gs_focusedWindow = this; - if ( IsShownOnScreen() ) + if ( IsShownOnScreen() && + (!oldFocusedWindow || oldFocusedWindow->GetTLW() != m_tlw) ) { m_tlw->SetDfbFocus(); } -- 2.47.2