1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/containr.cpp
3 // Purpose:     implementation of wxControlContainer
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     06.08.01
7 // Copyright:   (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
8 // Licence:     wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 #ifdef __BORLANDC__
23     #pragma hdrstop
24 #endif
25 
26 #ifndef WX_PRECOMP
27     #include "wx/containr.h"
28 #endif
29 
30 #ifndef WX_PRECOMP
31     #include "wx/log.h"
32     #include "wx/event.h"
33     #include "wx/window.h"
34     #include "wx/scrolbar.h"
35     #include "wx/radiobut.h"
36 #endif //WX_PRECOMP
37 
38 // trace mask for focus messages
39 #define TRACE_FOCUS wxT("focus")
40 
41 // ============================================================================
42 // implementation
43 // ============================================================================
44 
45 // ----------------------------------------------------------------------------
46 // wxControlContainerBase
47 // ----------------------------------------------------------------------------
48 
UpdateParentCanFocus()49 void wxControlContainerBase::UpdateParentCanFocus()
50 {
51     // In the ports where it does something non trivial, the parent window
52     // should only be focusable if it doesn't have any focusable children
53     // (e.g. native focus handling in wxGTK totally breaks down otherwise).
54     m_winParent->SetCanFocus(m_acceptsFocusSelf && !m_acceptsFocusChildren);
55 }
56 
UpdateCanFocusChildren()57 bool wxControlContainerBase::UpdateCanFocusChildren()
58 {
59     const bool acceptsFocusChildren = HasAnyFocusableChildren();
60     if ( acceptsFocusChildren != m_acceptsFocusChildren )
61     {
62         m_acceptsFocusChildren = acceptsFocusChildren;
63 
64         UpdateParentCanFocus();
65     }
66 
67     return m_acceptsFocusChildren;
68 }
69 
HasAnyFocusableChildren() const70 bool wxControlContainerBase::HasAnyFocusableChildren() const
71 {
72     const wxWindowList& children = m_winParent->GetChildren();
73     for ( wxWindowList::const_iterator i = children.begin(),
74                                      end = children.end();
75           i != end;
76           ++i )
77     {
78         const wxWindow * const child = *i;
79 
80         if ( !m_winParent->IsClientAreaChild(child) )
81             continue;
82 
83         // Here we check whether the child can accept the focus at all, as we
84         // want to try focusing it later even if it can't accept it right now.
85         if ( child->AcceptsFocusRecursively() )
86             return true;
87     }
88 
89     return false;
90 }
91 
HasAnyChildrenAcceptingFocus() const92 bool wxControlContainerBase::HasAnyChildrenAcceptingFocus() const
93 {
94     const wxWindowList& children = m_winParent->GetChildren();
95     for ( wxWindowList::const_iterator i = children.begin(),
96                                      end = children.end();
97           i != end;
98           ++i )
99     {
100         const wxWindow * const child = *i;
101 
102         if ( !m_winParent->IsClientAreaChild(child) )
103             continue;
104 
105         // Here we check if the child accepts focus right now as we need to
106         // know if we can give the focus to it or not.
107         if ( child->CanAcceptFocus() )
108             return true;
109     }
110 
111     return false;
112 }
113 
DoSetFocus()114 bool wxControlContainerBase::DoSetFocus()
115 {
116     wxLogTrace(TRACE_FOCUS, wxT("SetFocus on wxPanel 0x%p."),
117                m_winParent->GetHandle());
118 
119     if (m_inSetFocus)
120         return true;
121 
122     // when the panel gets the focus we move the focus to either the last
123     // window that had the focus or the first one that can get it unless the
124     // focus had been already set to some other child
125 
126     wxWindow *win = wxWindow::FindFocus();
127     while ( win )
128     {
129         if ( win == m_winParent )
130         {
131             // our child already has focus, don't take it away from it
132             return true;
133         }
134 
135         if ( win->IsTopLevel() )
136         {
137             // don't look beyond the first top level parent - useless and
138             // unnecessary
139             break;
140         }
141 
142         win = win->GetParent();
143     }
144 
145     // protect against infinite recursion:
146     m_inSetFocus = true;
147 
148     bool ret = SetFocusToChild();
149 
150     m_inSetFocus = false;
151 
152     return ret;
153 }
154 
AcceptsFocus() const155 bool wxControlContainerBase::AcceptsFocus() const
156 {
157     return m_acceptsFocusSelf && m_winParent->CanBeFocused();
158 }
159 
SetFocusToChild()160 bool wxControlContainerBase::SetFocusToChild()
161 {
162     return wxSetFocusToChild(m_winParent, &m_winLastFocused);
163 }
164 
165 #ifndef wxHAS_NATIVE_TAB_TRAVERSAL
166 
167 // ----------------------------------------------------------------------------
168 // generic wxControlContainer
169 // ----------------------------------------------------------------------------
170 
wxControlContainer()171 wxControlContainer::wxControlContainer()
172 {
173     m_winLastFocused = NULL;
174 }
175 
SetLastFocus(wxWindow * win)176 void wxControlContainer::SetLastFocus(wxWindow *win)
177 {
178     // the panel itself should never get the focus at all but if it does happen
179     // temporarily (as it seems to do under wxGTK), at the very least don't
180     // forget our previous m_winLastFocused
181     if ( win != m_winParent )
182     {
183         // if we're setting the focus
184         if ( win )
185         {
186             // find the last _immediate_ child which got focus
187             wxWindow *winParent = win;
188             while ( winParent != m_winParent )
189             {
190                 win = winParent;
191                 winParent = win->GetParent();
192 
193                 // Yes, this can happen, though in a totally pathological case.
194                 // like when detaching a menubar from a frame with a child
195                 // which has pushed itself as an event handler for the menubar.
196                 // (under wxGTK)
197 
198                 wxASSERT_MSG( winParent,
199                               wxT("Setting last focus for a window that is not our child?") );
200             }
201         }
202 
203         m_winLastFocused = win;
204 
205         if ( win )
206         {
207             wxLogTrace(TRACE_FOCUS, wxT("Set last focus to %s(%s)"),
208                        win->GetClassInfo()->GetClassName(),
209                        win->GetLabel().c_str());
210         }
211         else
212         {
213             wxLogTrace(TRACE_FOCUS, wxT("No more last focus"));
214         }
215     }
216 }
217 
218 // --------------------------------------------------------------------
219 // The following four functions are used to find other radio buttons
220 // within the same group. Used by wxSetFocusToChild on wxMSW
221 // --------------------------------------------------------------------
222 
223 #if wxUSE_RADIOBTN
224 
wxGetPreviousButtonInGroup(wxRadioButton * btn)225 wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn)
226 {
227     if ( btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) )
228         return NULL;
229 
230     const wxWindowList& siblings = btn->GetParent()->GetChildren();
231     wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn);
232     wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") );
233 
234     // Iterate over all previous siblings until we find the next radio button
235     wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
236     wxRadioButton *prevBtn = 0;
237     while (nodeBefore)
238     {
239         prevBtn = wxDynamicCast(nodeBefore->GetData(), wxRadioButton);
240         if (prevBtn)
241             break;
242 
243         nodeBefore = nodeBefore->GetPrevious();
244     }
245 
246     if (!prevBtn || prevBtn->HasFlag(wxRB_SINGLE))
247     {
248         // no more buttons in group
249         return NULL;
250     }
251 
252     return prevBtn;
253 }
254 
wxGetNextButtonInGroup(wxRadioButton * btn)255 wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn)
256 {
257     if (btn->HasFlag(wxRB_SINGLE))
258         return NULL;
259 
260     const wxWindowList& siblings = btn->GetParent()->GetChildren();
261     wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn);
262     wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") );
263 
264     // Iterate over all previous siblings until we find the next radio button
265     wxWindowList::compatibility_iterator nodeNext = nodeThis->GetNext();
266     wxRadioButton *nextBtn = 0;
267     while (nodeNext)
268     {
269         nextBtn = wxDynamicCast(nodeNext->GetData(), wxRadioButton);
270         if (nextBtn)
271             break;
272 
273         nodeNext = nodeNext->GetNext();
274     }
275 
276     if ( !nextBtn || nextBtn->HasFlag(wxRB_GROUP) || nextBtn->HasFlag(wxRB_SINGLE) )
277     {
278         // no more buttons or the first button of the next group
279         return NULL;
280     }
281 
282     return nextBtn;
283 }
284 
wxGetFirstButtonInGroup(wxRadioButton * btn)285 wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn)
286 {
287     while (true)
288     {
289         wxRadioButton* prevBtn = wxGetPreviousButtonInGroup(btn);
290         if (!prevBtn)
291             return btn;
292 
293         btn = prevBtn;
294     }
295 }
296 
wxGetLastButtonInGroup(wxRadioButton * btn)297 wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn)
298 {
299     while (true)
300     {
301         wxRadioButton* nextBtn = wxGetNextButtonInGroup(btn);
302         if (!nextBtn)
303             return btn;
304 
305         btn = nextBtn;
306     }
307 }
308 
wxGetSelectedButtonInGroup(wxRadioButton * btn)309 wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn)
310 {
311     // Find currently selected button
312     if (btn->GetValue())
313         return btn;
314 
315     if (btn->HasFlag(wxRB_SINGLE))
316         return NULL;
317 
318     wxRadioButton *selBtn;
319 
320     // First check all previous buttons
321     for (selBtn = wxGetPreviousButtonInGroup(btn); selBtn; selBtn = wxGetPreviousButtonInGroup(selBtn))
322         if (selBtn->GetValue())
323             return selBtn;
324 
325     // Now all following buttons
326     for (selBtn = wxGetNextButtonInGroup(btn); selBtn; selBtn = wxGetNextButtonInGroup(selBtn))
327         if (selBtn->GetValue())
328             return selBtn;
329 
330     return NULL;
331 }
332 
333 #endif // __WXMSW__
334 
335 // ----------------------------------------------------------------------------
336 // Keyboard handling - this is the place where the TAB traversal logic is
337 // implemented. As this code is common to all ports, this ensures consistent
338 // behaviour even if we don't specify how exactly the wxNavigationKeyEvent are
339 // generated and this is done in platform specific code which also ensures that
340 // we can follow the given platform standards.
341 // ----------------------------------------------------------------------------
342 
HandleOnNavigationKey(wxNavigationKeyEvent & event)343 void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event )
344 {
345     // for a TLW we shouldn't involve the parent window, it has nothing to do
346     // with keyboard navigation inside this TLW
347     wxWindow *parent = m_winParent->IsTopLevel() ? NULL
348                                                  : m_winParent->GetParent();
349 
350     // the event is propagated downwards if the event emitter was our parent
351     bool goingDown = event.GetEventObject() == parent;
352 
353     const wxWindowList& children = m_winParent->GetChildren();
354 
355     // if we have exactly one notebook-like child window (actually it could be
356     // any window that returns true from its HasMultiplePages()), then
357     // [Shift-]Ctrl-Tab and Ctrl-PageUp/Down keys should iterate over its pages
358     // even if the focus is outside of the control because this is how the
359     // standard MSW properties dialogs behave and we do it under other platforms
360     // as well because it seems like a good idea -- but we can always put this
361     // block inside "#ifdef __WXMSW__" if it's not suitable there
362     if ( event.IsWindowChange() && !goingDown )
363     {
364         // check if we have a unique notebook-like child
365         wxWindow *bookctrl = NULL;
366         for ( wxWindowList::const_iterator i = children.begin(),
367                                          end = children.end();
368               i != end;
369               ++i )
370         {
371             wxWindow * const window = *i;
372             if ( window->HasMultiplePages() )
373             {
374                 if ( bookctrl )
375                 {
376                     // this is the second book-like control already so don't do
377                     // anything as we don't know which one should have its page
378                     // changed
379                     bookctrl = NULL;
380                     break;
381                 }
382 
383                 bookctrl = window;
384             }
385         }
386 
387         if ( bookctrl )
388         {
389             // make sure that we don't bubble up the event again from the book
390             // control resulting in infinite recursion
391             wxNavigationKeyEvent eventCopy(event);
392             eventCopy.SetEventObject(m_winParent);
393             if ( bookctrl->GetEventHandler()->ProcessEvent(eventCopy) )
394                 return;
395         }
396     }
397 
398     // there is not much to do if we don't have children and we're not
399     // interested in "notebook page change" events here
400     if ( !children.GetCount() || event.IsWindowChange() )
401     {
402         // let the parent process it unless it already comes from our parent
403         // of we don't have any
404         if ( goingDown ||
405              !parent || !parent->GetEventHandler()->ProcessEvent(event) )
406         {
407             event.Skip();
408         }
409 
410         return;
411     }
412 
413     // where are we going?
414     const bool forward = event.GetDirection();
415 
416     // the node of the children list from which we should start looking for the
417     // next acceptable child
418     wxWindowList::compatibility_iterator node, start_node;
419 
420     // we should start from the first/last control and not from the one which
421     // had focus the last time if we're propagating the event downwards because
422     // for our parent we look like a single control
423     if ( goingDown )
424     {
425         // just to be sure it's not used (normally this is not necessary, but
426         // doesn't hurt neither)
427         m_winLastFocused = NULL;
428 
429         // start from first or last depending on where we're going
430         node = forward ? children.GetFirst() : children.GetLast();
431     }
432     else // going up
433     {
434         // try to find the child which has the focus currently
435 
436         // the event emitter might have done this for us
437         wxWindow *winFocus = event.GetCurrentFocus();
438 
439         // but if not, we might know where the focus was ourselves
440         if (!winFocus)
441             winFocus = m_winLastFocused;
442 
443         // if still no luck, do it the hard way
444         if (!winFocus)
445             winFocus = wxWindow::FindFocus();
446 
447         if ( winFocus )
448         {
449 #if defined(__WXMSW__) && wxUSE_RADIOBTN
450             // If we are in a radio button group, start from the first item in the
451             // group
452             if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) )
453                 winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus);
454 #endif // __WXMSW__
455             // ok, we found the focus - now is it our child?
456             start_node = children.Find( winFocus );
457         }
458 
459         if ( !start_node && m_winLastFocused )
460         {
461             // window which has focus isn't our child, fall back to the one
462             // which had the focus the last time
463             start_node = children.Find( m_winLastFocused );
464         }
465 
466         // if we still didn't find anything, we should start with the first one
467         if ( !start_node )
468         {
469             start_node = children.GetFirst();
470         }
471 
472         // and the first child which we can try setting focus to is the next or
473         // the previous one
474         node = forward ? start_node->GetNext() : start_node->GetPrevious();
475     }
476 
477     // we want to cycle over all elements passing by NULL
478     for ( ;; )
479     {
480         // don't go into infinite loop
481         if ( start_node && node && node == start_node )
482             break;
483 
484         // Have we come to the last or first item on the panel?
485         if ( !node )
486         {
487             if ( !start_node )
488             {
489                 // exit now as otherwise we'd loop forever
490                 break;
491             }
492 
493             if ( !goingDown )
494             {
495                 // Check if our (maybe grand) parent is another panel: if this
496                 // is the case, they will know what to do with this navigation
497                 // key and so give them the chance to process it instead of
498                 // looping inside this panel (normally, the focus will go to
499                 // the next/previous item after this panel in the parent
500                 // panel).
501                 wxWindow *focusedParent = m_winParent;
502                 while ( parent )
503                 {
504                     // We don't want to tab into a different dialog or frame or
505                     // even an MDI child frame, so test for this explicitly
506                     // (and in particular don't just use IsTopLevel() which
507                     // would return false in the latter case).
508                     if ( focusedParent->IsTopNavigationDomain() )
509                         break;
510 
511                     event.SetCurrentFocus( focusedParent );
512                     if ( parent->GetEventHandler()->ProcessEvent( event ) )
513                         return;
514 
515                     focusedParent = parent;
516 
517                     parent = parent->GetParent();
518                 }
519             }
520             //else: as the focus came from our parent, we definitely don't want
521             //      to send it back to it!
522 
523             // no, we are not inside another panel so process this ourself
524             node = forward ? children.GetFirst() : children.GetLast();
525 
526             continue;
527         }
528 
529         wxWindow *child = node->GetData();
530 
531         // don't TAB to another TLW
532         if ( child->IsTopLevel() )
533         {
534             node = forward ? node->GetNext() : node->GetPrevious();
535 
536             continue;
537         }
538 
539 #if defined(__WXMSW__) && wxUSE_RADIOBTN
540         if ( event.IsFromTab() )
541         {
542             if ( wxIsKindOf(child, wxRadioButton) )
543             {
544                 // only radio buttons with either wxRB_GROUP or wxRB_SINGLE
545                 // can be tabbed to
546                 if ( child->HasFlag(wxRB_GROUP) )
547                 {
548                     // need to tab into the active button within a group
549                     wxRadioButton *rb = wxGetSelectedButtonInGroup((wxRadioButton*)child);
550                     if ( rb )
551                         child = rb;
552                 }
553                 else if ( !child->HasFlag(wxRB_SINGLE) )
554                 {
555                     node = forward ? node->GetNext() : node->GetPrevious();
556                     continue;
557                 }
558             }
559         }
560         else if ( m_winLastFocused &&
561                   wxIsKindOf(m_winLastFocused, wxRadioButton) &&
562                   !m_winLastFocused->HasFlag(wxRB_SINGLE) )
563         {
564             wxRadioButton * const
565                 lastBtn = static_cast<wxRadioButton *>(m_winLastFocused);
566 
567             // cursor keys don't navigate out of a radio button group so
568             // find the correct radio button to focus
569             if ( forward )
570             {
571                 child = wxGetNextButtonInGroup(lastBtn);
572                 if ( !child )
573                 {
574                     // no next button in group, set it to the first button
575                     child = wxGetFirstButtonInGroup(lastBtn);
576                 }
577             }
578             else
579             {
580                 child = wxGetPreviousButtonInGroup(lastBtn);
581                 if ( !child )
582                 {
583                     // no previous button in group, set it to the last button
584                     child = wxGetLastButtonInGroup(lastBtn);
585                 }
586             }
587 
588             if ( child == m_winLastFocused )
589             {
590                 // must be a group consisting of only one button therefore
591                 // no need to send a navigation event
592                 event.Skip(false);
593                 return;
594             }
595         }
596 #endif // __WXMSW__
597 
598         if ( child->CanAcceptFocusFromKeyboard() )
599         {
600             // if we're setting the focus to a child panel we should prevent it
601             // from giving it to the child which had the focus the last time
602             // and instead give it to the first/last child depending from which
603             // direction we're coming
604             event.SetEventObject(m_winParent);
605 
606             // disable propagation for this call as otherwise the event might
607             // bounce back to us.
608             wxPropagationDisabler disableProp(event);
609             if ( !child->GetEventHandler()->ProcessEvent(event) )
610             {
611                 // set it first in case SetFocusFromKbd() results in focus
612                 // change too
613                 m_winLastFocused = child;
614 
615                 // everything is simple: just give focus to it
616                 child->SetFocusFromKbd();
617             }
618             //else: the child manages its focus itself
619 
620             event.Skip( false );
621 
622             return;
623         }
624 
625         node = forward ? node->GetNext() : node->GetPrevious();
626     }
627 
628     // we cycled through all of our children and none of them wanted to accept
629     // focus
630     event.Skip();
631 }
632 
HandleOnWindowDestroy(wxWindowBase * child)633 void wxControlContainer::HandleOnWindowDestroy(wxWindowBase *child)
634 {
635     if ( child == m_winLastFocused )
636         m_winLastFocused = NULL;
637 }
638 
639 // ----------------------------------------------------------------------------
640 // focus handling
641 // ----------------------------------------------------------------------------
642 
HandleOnFocus(wxFocusEvent & event)643 void wxControlContainer::HandleOnFocus(wxFocusEvent& event)
644 {
645     wxLogTrace(TRACE_FOCUS, wxT("OnFocus on wxPanel 0x%p, name: %s"),
646                m_winParent->GetHandle(),
647                m_winParent->GetName().c_str() );
648 
649     DoSetFocus();
650 
651     event.Skip();
652 }
653 
654 
655 #else
656   // wxHAS_NATIVE_TAB_TRAVERSAL
657 
SetFocusToChild()658 bool wxControlContainer::SetFocusToChild()
659 {
660     return wxSetFocusToChild(m_winParent, NULL);
661 }
662 
663 
664 #endif // !wxHAS_NATIVE_TAB_TRAVERSAL
665 
666 // ----------------------------------------------------------------------------
667 // SetFocusToChild(): this function is used by wxPanel but also by wxFrame in
668 // wxMSW, this is why it is outside of wxControlContainer class
669 // ----------------------------------------------------------------------------
670 
wxSetFocusToChild(wxWindow * win,wxWindow ** childLastFocused)671 bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused)
672 {
673     wxCHECK_MSG( win, false, wxT("wxSetFocusToChild(): invalid window") );
674     //    wxCHECK_MSG( childLastFocused, false,
675     //             wxT("wxSetFocusToChild(): NULL child poonter") );
676 
677     if ( childLastFocused && *childLastFocused )
678     {
679         // It might happen that the window got reparented
680         if ( (*childLastFocused)->GetParent() == win )
681         {
682             // And it also could have become hidden in the meanwhile
683             // We want to focus on the deepest widget visible
684             wxWindow *deepestVisibleWindow = NULL;
685 
686             while ( *childLastFocused )
687             {
688                 if ( (*childLastFocused)->IsShown() )
689                 {
690                     if ( !deepestVisibleWindow )
691                         deepestVisibleWindow = *childLastFocused;
692                 }
693                 else
694                     deepestVisibleWindow = NULL;
695 
696                 *childLastFocused = (*childLastFocused)->GetParent();
697             }
698 
699             if ( deepestVisibleWindow )
700             {
701                 *childLastFocused = deepestVisibleWindow;
702 
703                 wxLogTrace(TRACE_FOCUS,
704                            wxT("SetFocusToChild() => last child (0x%p)."),
705                            (*childLastFocused)->GetHandle());
706 
707                 // not SetFocusFromKbd(): we're restoring focus back to the old
708                 // window and not setting it as the result of a kbd action
709                 (*childLastFocused)->SetFocus();
710                 return true;
711             }
712         }
713         else
714         {
715             // it doesn't count as such any more
716             *childLastFocused = NULL;
717         }
718     }
719 
720     // set the focus to the first child who wants it
721     wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
722     while ( node )
723     {
724         wxWindow *child = node->GetData();
725         node = node->GetNext();
726 
727         // skip special windows:
728         if ( !win->IsClientAreaChild(child) )
729             continue;
730 
731         if ( child->CanAcceptFocusFromKeyboard() && !child->IsTopLevel() )
732         {
733 #if defined(__WXMSW__) && wxUSE_RADIOBTN
734             // If a radiobutton is the first focusable child, search for the
735             // selected radiobutton in the same group
736             wxRadioButton* btn = wxDynamicCast(child, wxRadioButton);
737             if (btn)
738             {
739                 wxRadioButton* selected = wxGetSelectedButtonInGroup(btn);
740                 if (selected)
741                     child = selected;
742             }
743 #endif // __WXMSW__
744 
745             wxLogTrace(TRACE_FOCUS,
746                        wxT("SetFocusToChild() => first child (0x%p)."),
747                        child->GetHandle());
748 
749             if (childLastFocused)
750                 *childLastFocused = child;
751             child->SetFocusFromKbd();
752             return true;
753         }
754     }
755 
756     return false;
757 }
758 
759