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
This commit is contained in:
Václav Slavík
2007-06-28 12:57:17 +00:00
parent 42fc0309be
commit fd2be5df8d
3 changed files with 75 additions and 4 deletions

View File

@@ -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:

View File

@@ -200,6 +200,8 @@ void wxTopLevelWindowDFB::HandleFocusEvent(const wxDFBWindowEvent& event_)
if ( CanAcceptFocus() )
SetFocus();
else
wxLogTrace(TRACE_EVENTS, "...which doesn't accept it");
}
}
}

View File

@@ -194,7 +194,8 @@ void wxWindowDFB::SetFocus()
gs_focusedWindow = this;
if ( IsShownOnScreen() )
if ( IsShownOnScreen() &&
(!oldFocusedWindow || oldFocusedWindow->GetTLW() != m_tlw) )
{
m_tlw->SetDfbFocus();
}