]> git.saurik.com Git - wxWidgets.git/blobdiff - src/dfb/nonownedwnd.cpp
Fixed wxAtomicInc/Dec() to not use asm/atomic.h header on Linux - it's kernel interna...
[wxWidgets.git] / src / dfb / nonownedwnd.cpp
index 4fe1ac999d6229480c06b994928c7f4a3094eba2..3652a13ba470f0ebd491ac901d434b5e8e51f130 100644 (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$
@@ -21,8 +21,8 @@
 #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
@@ -101,14 +101,14 @@ bool wxNonOwnedWindow::Create(wxWindow *parent,
                                  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)
@@ -244,18 +244,16 @@ bool wxNonOwnedWindow::Show(bool show)
 
     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;
@@ -309,7 +307,7 @@ void wxNonOwnedWindow::HandleQueuedPaintRequests()
             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());
 
@@ -348,7 +346,7 @@ void wxNonOwnedWindow::HandleQueuedPaintRequests()
     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,
@@ -364,7 +362,7 @@ void wxNonOwnedWindow::DoRefreshRect(const wxRect& rect)
         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());
 
@@ -381,11 +379,65 @@ 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") );
+    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();
 }
@@ -398,47 +450,49 @@ void wxNonOwnedWindow::HandleDFBWindowEvent(const wxDFBWindowEvent& event_)
     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_);
 }
 
 // ---------------------------------------------------------------------------