wxWidgets / wxWidgets

Cross-Platform C++ GUI Library
https://www.wxwidgets.org/
6.17k stars 1.77k forks source link

wxPanel::SetFocusIgnoringChildren has invalid behaviour in wxWidgets-GTK 2.9 #14263

Open wxtrac opened 12 years ago

wxtrac commented 12 years ago

Issue migrated from trac ticket # 14263

component: wxGTK | priority: normal

2012-05-02 17:41:44: Chuddah (Damien Ruscoe) created the issue


The behaviour of SetFocusIgnoringChildren now boils down to wxWindow::SetFocus which calls gtk_widget_child_focus(widget, GTK_DIR_TAB_FORWARD)

In other words; trying to explicitly set focus to a panel [not a child control] with child windows causes a tab traversal to take place.

Attached is a demo of this problem

wxtrac commented 12 years ago

2012-05-02 17:42:08: Chuddah (Damien Ruscoe) uploaded file panel_children_focus_issue.py (1.1 KiB)

Demo of the bug

wxtrac commented 12 years ago

2012-05-04 12:39:49: Chuddah (Damien Ruscoe) uploaded file window.patch (0.4 KiB)

A fix

wxtrac commented 12 years ago

2012-05-04 12:42:39: Chuddah (Damien Ruscoe) commented


I have attached a fix which seems to resolve this problem. It is a modification of some code that has removed since wxPython2.8

Although this patch solves the problem demonstrated in the demo of the bug, I am completely uncertain of what adverse effect that this may have.

I have posted this here for someone with a little more experience of this codebase to take a look at.

wxtrac commented 12 years ago

2012-05-09 16:09:14: @vadz changed priority from normal to low

2012-05-09 16:09:14: @vadz changed status from new to confirmed

2012-05-09 16:09:14: @vadz commented

We clearly do need to allow SetFocusIgnoringChildren() to work but the patch actually doesn't seem to solve the problem for me. If I do this:

#!diff
diff --git a/samples/minimal/minimal.cpp b/samples/minimal/minimal.cpp
index a78e462..8b001dc 100644
--- a/samples/minimal/minimal.cpp
+++ b/samples/minimal/minimal.cpp
@@ -141,6 +141,8 @@ bool MyApp::OnInit()
 // main frame
 // ----------------------------------------------------------------------------

+wxPanel* p;
+
 // frame constructor
 MyFrame::MyFrame(const wxString& title)
        : wxFrame(NULL, wxID_ANY, title)
@@ -167,6 +169,10 @@ bool MyApp::OnInit()
     SetMenuBar(menuBar);
 #endif // wxUSE_MENUS

+    p = new wxPanel(this);
+    new wxStaticText(p, wxID_ANY, "Label", wxPoint(5, 5));
+    new wxButton(p, wxID_OK, "", wxPoint(5, 35));
+
 #if wxUSE_STATUSBAR
     // create a status bar just for fun (by default with 1 pane only)
     CreateStatusBar(2);
@@ -185,6 +191,9 @@ void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))

 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
 {
+    p->SetFocusIgnoringChildren();
+    return;
+
     wxMessageBox(wxString::Format
                  (
                     "Welcome to %s!\n"

And run the program as WXTRACE=focus ./minimal I see that the focus is being set to the panel but actually the button still remains focused, so it looks like we're missing something (gtk_widget_set_can_focus() call?) at GTK level.

Paul, any idea about how to make this work?

wxtrac commented 10 years ago

2014-11-14 03:21:40: @paulcor changed priority from low to normal

2014-11-14 03:21:40: @paulcor commented

Since 52473, SetFocus() on a plain wxWindow (or similar, such as wxPanel) does not work unless you call SetCanFocus(true). The documentation for SetCanFocus() says "A call to this does not disable or change the effect of programmatically calling SetFocus()", so that's currently wrong.

We could call gtk_widget_set_can_focus(m_wxwindow, true) in Create(). I'm a little nervous about what other effects that might have though. And it doesn't address SetCanFocus(). This focus code is a mess.

wxtrac commented 10 years ago

2014-11-18 08:41:33: @paulcor commented


It turns out wxWindowGTK::Create() already calls SetCanFocus(AcceptsFocus()), so focus is enabled for wxPanel, but when a child is added, wxControlContainerBase::UpdateParentCanFocus() turns it back off. Which means SetFocusIgnoringChildren() won't work.

And plain wxWindow is not affected, I was fooled by wxScrolledWindow, which is not (any more?) a scrolled wxWindow but a scrolled wxPanel.

wxtrac commented 10 years ago

2014-11-18 14:01:01: @vadz commented


The problem here is that for me all "can focus" stuff originally meant "can be given focus by the user", but for GTK+ it clearly means "can be focused at all". We need to decide which interpretation does wx API really implement. If it's impossible to have a window accept focus without accepting it from the user, then, I guess, the decision is already made and we just need to update the documentation and maybe ensure that SetFocus() doesn't work for unfocusable windows in wxMSW and the other ports neither.

What do you think?