]> git.saurik.com Git - wxWidgets.git/commitdiff
fixes to handling of focus changes for toplevel windows
authorVáclav Slavík <vslavik@fastmail.fm>
Thu, 28 Jun 2007 12:57:17 +0000 (12:57 +0000)
committerVáclav Slavík <vslavik@fastmail.fm>
Thu, 28 Jun 2007 12:57:17 +0000 (12:57 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@46998 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

src/dfb/nonownedwnd.cpp
src/dfb/toplevel.cpp
src/dfb/window.cpp

index 35e8d3fd741200f9c5daad0429cce96c70f17c4a..58d59ebebcd515e416dc864c21e819a7f21e9d99 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$
@@ -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:
index c8c36de1f16acb34b47c367a6207059f23719d06..cb557cc2c380985ea7dcd1292a45338658d6c322 100644 (file)
@@ -200,6 +200,8 @@ void wxTopLevelWindowDFB::HandleFocusEvent(const wxDFBWindowEvent& event_)
 
             if ( CanAcceptFocus() )
                 SetFocus();
+            else
+                wxLogTrace(TRACE_EVENTS, "...which doesn't accept it");
         }
     }
 }
index b3f8121c5eb4487672ee5ef8bc690b2aaae05b12..f82ffb8ed60ecb344ba970291cd8f6bf10a93e52 100644 (file)
@@ -194,7 +194,8 @@ void wxWindowDFB::SetFocus()
 
     gs_focusedWindow = this;
 
-    if ( IsShownOnScreen() )
+    if ( IsShownOnScreen() &&
+         (!oldFocusedWindow || oldFocusedWindow->GetTLW() != m_tlw) )
     {
         m_tlw->SetDfbFocus();
     }