/////////////////////////////////////////////////////////////////////////////
// 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_sizeSet = true;
wxSizeEvent event(GetSize(), GetId());
event.SetEventObject(this);
- GetEventHandler()->ProcessEvent(event);
+ HandleWindowEvent(event);
}
// make sure the window is fully painted, with all pending updates, before
if ( show )
{
- wxWindow *focused = wxWindow::FindFocus();
+ wxWindow *focused = FindFocus();
if ( focused && focused->GetTLW() == this )
{
+ // focus is on this frame or its children, apply it to DirectFB
SetDfbFocus();
}
- else if ( AcceptsFocus() )
- {
- // FIXME: we should probably always call SetDfbFocus instead
- // and call SetFocus() from wxActivateEvent/DWET_GOTFOCUS
- // handler
- SetFocus();
- }
+ // 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;
}
wxNonOwnedWindow *tlw = gs_dfbWindowsMap[event.window_id];
- wxWindow *recipient = NULL;
- void (wxWindow::*handlerFunc)(const wxDFBWindowEvent&) = NULL;
switch ( event.type )
{
case DWET_KEYDOWN:
case DWET_KEYUP:
{
- recipient = wxWindow::FindFocus();
- handlerFunc = &wxWindowDFB::HandleKeyEvent;
+ wxWindow *recipient = wxWindow::FindFocus();
+ if ( !recipient )
+ {
+ wxLogTrace(TRACE_EVENTS,
+ "ignoring event: no recipient window");
+ return;
+ }
+
+ wxCHECK_RET( recipient && recipient->GetTLW() == tlw,
+ "event recipient not in TLW which received the event" );
+
+ recipient->HandleKeyEvent(event_);
break;
}
+ case DWET_GOTFOCUS:
+ case DWET_LOSTFOCUS:
+ {
+ 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:
// we're not interested in them here
break;
}
-
- if ( !recipient )
- {
- wxLogTrace(TRACE_EVENTS, _T("ignoring event: no recipient window"));
- return;
- }
-
- wxCHECK_RET( recipient && recipient->GetTLW() == tlw,
- _T("event recipient not in TLW which received the event") );
-
- // process the event:
- (recipient->*handlerFunc)(event_);
}
// ---------------------------------------------------------------------------