/////////////////////////////////////////////////////////////////////////////
// Name: src/dfb/nonownedwnd.cpp
-// Purpose: implementation of wxNonOwnedWindowow
+// Purpose: implementation of wxNonOwnedWindow
// Author: Vaclav Slavik
// Created: 2006-12-24
// RCS-ID: $Id$
#include "wx/evtloop.h"
#include "wx/dfb/private.h"
-#define TRACE_EVENTS _T("events")
-#define TRACE_PAINT _T("paint")
+#define TRACE_EVENTS "events"
+#define TRACE_PAINT "paint"
// ============================================================================
// globals
long style,
const wxString &name)
{
- wxCHECK_MSG( pos.x >= 0 && pos.y >= 0, false, _T("invalid position") );
- wxCHECK_MSG( size.x > 0 && size.y > 0, false, _T("invalid size") );
+ wxCHECK_MSG( pos.x >= 0 && pos.y >= 0, false, "invalid position" );
+ wxCHECK_MSG( size.x > 0 && size.y > 0, false, "invalid size" );
m_tlw = this;
// create DirectFB window:
wxIDirectFBDisplayLayerPtr layer(wxIDirectFB::Get()->GetDisplayLayer());
- wxCHECK_MSG( layer, false, _T("no display layer") );
+ wxCHECK_MSG( layer, false, "no display layer" );
DFBWindowDescription desc;
desc.flags = (DFBWindowDescriptionFlags)
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;
}
continue; // nothing to refresh
wxLogTrace(TRACE_PAINT,
- _T("%p ('%s'): processing paint request [%i,%i,%i,%i]"),
+ "%p ('%s'): processing paint request [%i,%i,%i,%i]",
this, GetName().c_str(),
clipped.x, clipped.y, clipped.GetRight(), clipped.GetBottom());
GetDfbSurface()->FlipToFront(rptr);
wxLogTrace(TRACE_PAINT,
- _T("%p ('%s'): processed %i paint requests, flipped surface: [%i,%i,%i,%i]"),
+ "%p ('%s'): processed %i paint requests, flipped surface: [%i,%i,%i,%i]",
this, GetName().c_str(),
requestsCount,
paintedRect.x, paintedRect.y,
return;
wxLogTrace(TRACE_PAINT,
- _T("%p ('%s'): [TLW] refresh rect [%i,%i,%i,%i]"),
+ "%p ('%s'): [TLW] refresh rect [%i,%i,%i,%i]",
this, GetName().c_str(),
rect.x, rect.y, rect.GetRight(), rect.GetBottom());
// 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") );
+ wxCHECK_RET( IsShown(), "cannot set focus to hidden window" );
wxASSERT_MSG( FindFocus() && FindFocus()->GetTLW() == this,
- _T("setting DirectFB focus to unexpected window") );
+ "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();
}
if ( gs_dfbWindowsMap.find(event.window_id) == gs_dfbWindowsMap.end() )
{
wxLogTrace(TRACE_EVENTS,
- _T("received event for unknown DirectFB window, ignoring"));
+ "received event for unknown DirectFB window, ignoring");
return;
}
if ( !recipient )
{
wxLogTrace(TRACE_EVENTS,
- _T("ignoring event: no recipient window"));
+ "ignoring event: no recipient window");
return;
}
wxCHECK_RET( recipient && recipient->GetTLW() == tlw,
- _T("event recipient not in TLW which received the event") );
+ "event recipient not in TLW which received the event" );
recipient->HandleKeyEvent(event_);
break;
case DWET_GOTFOCUS:
case DWET_LOSTFOCUS:
- tlw->HandleFocusEvent(event_);
+ {
+ InsideDFBFocusHandlerSetter inside(tlw);
+ tlw->HandleFocusEvent(event_);
+ }
break;
case DWET_NONE:
case DWET_ALL:
- wxFAIL_MSG( _T("invalid event type") );
+ wxFAIL_MSG( "invalid event type" );
break;
default: