Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 480794

Summary: [GTK3] TabFolder cannot be traversed with Tab key; TabFolder#getChildren() is empty
Product: [Eclipse Project] Platform Reporter: Markus Keller <markus.kell.r>
Component: SWTAssignee: Markus Keller <markus.kell.r>
Status: VERIFIED FIXED QA Contact:
Severity: major    
Priority: P3 CC: akurtakov, arunkumar.thondapu, daniel_megert, ericwill, isabellerichard89, Lars.Vogel, lufimtse, malaperle, markus.kell.r, patrick.tasse, peter, piotr.findeisen
Version: 4.5.1Flags: arunkumar.thondapu: review+
Target Milestone: 4.5.2   
Hardware: PC   
OS: Linux   
See Also: https://git.eclipse.org/r/59782
https://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?id=fb8bba31430f2cf26f6c4a4e51ed776390dfab95
Whiteboard:
Bug Depends on: 454936    
Bug Blocks: 474628    

Description Markus Keller CLA 2015-10-27 12:55:16 EDT
master, Ubuntu 12.04 32-bit

On GTK3 (3.4.2), a TabFolder cannot be traversed with the Tab key. In the ControlExample, in Snippet76, and in the Eclipse Search dialog, the Tab key doesn't move the focus.

Problem seems to be that tabFolder.getChildern() wrongly returns an empty array on GTK3.
Comment 1 Eric Williams CLA 2015-11-02 16:12:21 EST
It seems _getChildren in Composite is not correctly traversing the g_list in GTK3. I will investigate further.
Comment 2 Eric Williams CLA 2015-11-03 08:28:56 EST
*** Bug 481297 has been marked as a duplicate of this bug. ***
Comment 3 Piotr Findeisen CLA 2015-11-03 08:36:07 EST
Bug 481297 has been closed as duplicate of this one. Can this be updated as affecting 4.5.1?

Will this be solved in 4.5 maintenance? I must say impossibility to TAB in File Search strikes me several times a day.
Comment 4 Eric Williams CLA 2015-11-03 08:48:43 EST
(In reply to Piotr Findeisen from comment #3)
> Bug 481297 has been closed as duplicate of this one. Can this be updated as
> affecting 4.5.1?
> 
> Will this be solved in 4.5 maintenance? I must say impossibility to TAB in
> File Search strikes me several times a day.

Most likely, yes. This is a pretty major bug so once it's fixed it will probably be backported.
Comment 5 Markus Keller CLA 2015-11-03 10:48:00 EST
(In reply to Piotr Findeisen from comment #3)
> I must say impossibility to TAB in
> File Search strikes me several times a day.

You may want to go back to GTK2 until this is fixed.
Set environment variable SWT_GTK3 to 0 before starting Eclipse.
Comment 6 Piotr Findeisen CLA 2015-11-03 11:53:42 EST
(In reply to Markus Keller from comment #5)
> You may want to go back to GTK2 until this is fixed.
> Set environment variable SWT_GTK3 to 0 before starting Eclipse.

My Eclipse was freezing in "gtk os call" until i removed SWT_GTK3=0.
Comment 7 Markus Keller CLA 2015-11-03 13:12:53 EST
(In reply to Piotr Findeisen from comment #6)
> My Eclipse was freezing in "gtk os call" until i removed SWT_GTK3=0.

Please file a separate bug and attach stackdumps if you think your GTK2 libraries are installed correctly. GTK2 is still supposed to work.


(In reply to Eric Williams from comment #1)
> It seems _getChildren in Composite is not correctly traversing the g_list in
> GTK3. I will investigate further.

See bug 454936. The TabFolder class needs an implementation comment that points readers to the long "Architecture Fix" comment in TabItem.
Comment 8 Eric Williams CLA 2015-11-03 15:51:09 EST
(In reply to Markus Keller from comment #7)
> See bug 454936. The TabFolder class needs an implementation comment that
> points readers to the long "Architecture Fix" comment in TabItem.

Yes this is the issue. There is something wrong with the way we store Widgets in the widget table, because g_object_get_qdata() in Display.getWidget() doesn't return the widgets correctly when called by Composite._getChildren() (at least in the case of TabFolder/GtkNotebook).

I've managed to get the focus to switch properly with some hacky workarounds in Control.traverseGroup(). The focus switches properly once the proper TabFolder child widgets are populated into the list.

More investigation to follow.
Comment 9 Markus Keller CLA 2015-11-04 08:15:00 EST
Leo, Alex: It looks like bug 454936 was quite incomplete. I also think the ASCII-art in TabItem is not correct:

*  GTK3+:
*  	swtFixed
*  	|--	GtkNoteBook
*  		|-- tabLabel1
*  		|-- tabLabel2
*  		|-- swtFixed (child1) //child now child of Notebook.
*  		|-- swtFixed (child2)


Shouldn't it be like this?

*  GTK3+:
*  	swtFixed
*  	|--	GtkNoteBook
*  		|-- tabLabel1
*  		|-- tabLabel2
*  		|-- pageHandle (tabItem1)
*  			|-- child1 //child now child of Notebook.pageHandle.
*  		|-- pageHandle (tabItem2)
*  			|-- child1

Please make sure there's an SWT test case that verifies the result of TabFolder#getChildren(). It's currently always empty on GTK3.

TabFolder#minimumSize(int, int, boolean) is also wrong. E.g. change Snippet76 like this to create buttons of different heights:
 
		button.setText ("Page " + i + (i > 0 ? "\nLine 2": ""));

And also have a look at TabFolder#releaseChildren(..) again. That method calls super.releaseChildren(), which calls Composite#_getChildren() -- and the latter doesn't make sense any more in GTK3.
Comment 10 Eric Williams CLA 2015-11-04 08:38:15 EST
(In reply to Markus Keller from comment #9)
> Leo, Alex: It looks like bug 454936 was quite incomplete. I also think the
> ASCII-art in TabItem is not correct:
> 
> *  GTK3+:
> *  	swtFixed
> *  	|--	GtkNoteBook
> *  		|-- tabLabel1
> *  		|-- tabLabel2
> *  		|-- swtFixed (child1) //child now child of Notebook.
> *  		|-- swtFixed (child2)
> 
> 
> Shouldn't it be like this?
> 
> *  GTK3+:
> *  	swtFixed
> *  	|--	GtkNoteBook
> *  		|-- tabLabel1
> *  		|-- tabLabel2
> *  		|-- pageHandle (tabItem1)
> *  			|-- child1 //child now child of Notebook.pageHandle.
> *  		|-- pageHandle (tabItem2)
> *  			|-- child1

Technically these are the same, no? The swtFixed (child 1, 2) in Leo's original diagram represent the pageHandles (TabItems) which are children of TabFolder, (or GtkNotebook). The children of these pageHandles are the controls of those individual TabItems.

> which calls Composite#_getChildren() -- and
> the latter doesn't make sense any more in GTK3.

In the sense that the logic of calling it is incorrect, or because on GTK3 _getChildren() does not function as expected?
Comment 11 Markus Keller CLA 2015-11-04 09:32:02 EST
(In reply to Eric Williams from comment #10)
> Technically these are the same, no?

No, I think the GTK3 diagram shows what went wrong in the implementation. As I read the comment, "swtFixed" refers to Control#fixedHandle. The problem on GTK3 is that the TabItem#control objects are NOT children of that TabFolder#fixedHandle in GTK3, but they are children of each pageHandle. The current GTK3 diagram doesn't show that.

> > which calls Composite#_getChildren() -- and
> > the latter doesn't make sense any more in GTK3.
> 
> In the sense that the logic of calling it is incorrect, or because on GTK3
> _getChildren() does not function as expected?

It doesn't make sense to dispose of the TabItems and then try to dispose all _getChildren () again. You have to verify that disposing the TabItems also properly disposes of the TabItem#control objects and also properly releases the GTK3 objects (I don't know the protocol there). Then remove the unnecessary traversal of _getChildren ().
Comment 12 Eclipse Genie CLA 2015-11-05 10:36:39 EST
New Gerrit change created: https://git.eclipse.org/r/59753
Comment 13 Eric Williams CLA 2015-11-05 10:39:05 EST
(In reply to Markus Keller from comment #11)
> No, I think the GTK3 diagram shows what went wrong in the implementation. As
> I read the comment, "swtFixed" refers to Control#fixedHandle. The problem on
> GTK3 is that the TabItem#control objects are NOT children of that
> TabFolder#fixedHandle in GTK3, but they are children of each pageHandle. The
> current GTK3 diagram doesn't show that.

I understand now: you are correct, that diagram should be updated.

> It doesn't make sense to dispose of the TabItems and then try to dispose all
> _getChildren () again. You have to verify that disposing the TabItems also
> properly disposes of the TabItem#control objects and also properly releases
> the GTK3 objects (I don't know the protocol there). Then remove the
> unnecessary traversal of _getChildren ().

It seems there are more issues at play here, which warrant a separate investigation/fix of TabFolder/TabItem in general.

The reason this focus bug happens is because computeTabList() in Composite is called on itself as there are no overriding functions. When Control.traverseGroup() calls Shell.computeTabList(), it traverses down the Widget tree until it reaches the children of a TabFolder. The bug happens when it gets to TabFolder, at which point none of the children are returned (because of _getChildren() not working as expected).

We can override computeTabList() in TabFolder to correctly return the child controls to Control.traverseGroup(), which will fix the focus issue in GTK3.
Comment 14 Eric Williams CLA 2015-11-05 14:30:08 EST
(In reply to Eric Williams from comment #13)
> We can override computeTabList() in TabFolder to correctly return the child
> controls to Control.traverseGroup(), which will fix the focus issue in GTK3.

I've actually found a much cleaner solution: in Composite.computeTabList() we can simply call _getChildren() with TabFolder.clientHandle() as an argument.
Comment 15 Eclipse Genie CLA 2015-11-05 15:20:34 EST
New Gerrit change created: https://git.eclipse.org/r/59782
Comment 16 Markus Keller CLA 2015-11-05 15:28:00 EST
(In reply to Eric Williams from comment #14)
No. An "if (... instanceof ...)" in a superclass that checks for a subclass is always architecturally wrong. You should not try to fix one effect of the problem, but you should try to understand where the problem was introduced and then find a better fix for the original problem.

The reason for the focus bug and the wrong minimumSize(..) is that _getChildren() is broken. Here's a fix that reverts parts of bug 454936 and fixes _getChildren():

https://git.eclipse.org/r/59782

TODOs:
- move the description of the version-dependent architecture from TabItem#setControl(Control) to the beginning of TabFolder
- add regression tests
Comment 17 Markus Keller CLA 2015-11-05 15:31:17 EST
Looks like the final fix should also be backported to 4.4.2, see bug 453827 comment 11.
Comment 18 Eric Williams CLA 2015-11-05 15:42:31 EST
(In reply to Markus Keller from comment #16)
> (In reply to Eric Williams from comment #14)
> No. An "if (... instanceof ...)" in a superclass that checks for a subclass
> is always architecturally wrong. You should not try to fix one effect of the
> problem, but you should try to understand where the problem was introduced
> and then find a better fix for the original problem.
> 
> The reason for the focus bug and the wrong minimumSize(..) is that
> _getChildren() is broken. Here's a fix that reverts parts of bug 454936 and
> fixes _getChildren():

Fair point -- this is a much better fix.

> TODOs:
> - move the description of the version-dependent architecture from
> TabItem#setControl(Control) to the beginning of TabFolder
> - add regression tests

Will you be including these in this patch or should a separate bug be filed for the test cases + comment cleanup?
Comment 19 Eric Williams CLA 2015-11-09 09:54:17 EST
(In reply to Markus Keller from comment #16)
> - add regression tests

This patch solves the bug for me, but one of the Composite getChildren() tests fail:

Composite c1 = new Composite(composite, 0);
assertArrayEquals(":b:", new Control[]{c1}, composite.getChildren());

The expected result was 1 but getChildren() in this case returned 0.
Comment 21 Markus Keller CLA 2015-11-09 13:59:17 EST
(In reply to Eric Williams from comment #19)
Test_org_eclipse_swt_widgets_TabFolder#test_getChildren() doesn't make much sense for TabFolder. It just tests the corner case where children of TabFolder are created but not registered under a TabItem using #setControl(Control).

Fixed this in TabFolder#_getChildren(), moved implementation note to TabFolder, and added another test for getChildren().

Arun: OK to backport to 4.5.2? Bug 454936 introduced this accessibility issue.
Comment 22 Arun Thondapu CLA 2015-11-12 12:58:28 EST
(In reply to Markus Keller from comment #21)
> (In reply to Eric Williams from comment #19)
> Test_org_eclipse_swt_widgets_TabFolder#test_getChildren() doesn't make much
> sense for TabFolder. It just tests the corner case where children of
> TabFolder are created but not registered under a TabItem using
> #setControl(Control).
> 
> Fixed this in TabFolder#_getChildren(), moved implementation note to
> TabFolder, and added another test for getChildren().
> 
> Arun: OK to backport to 4.5.2? Bug 454936 introduced this accessibility
> issue.

+1 to backport to 4.5.2 and as mentioned in comment 17, should be backported to 4.4.2 as well... thanks Markus and Eric!
Comment 23 Marc-André Laperle CLA 2015-12-11 15:31:16 EST
Could someone backport this to 4.5? I would do it but I am not the author of the original patch or a committer so I can't push it to gerrit :) It will be a good fix for SWTBot too.
Comment 24 Arun Thondapu CLA 2016-01-06 14:20:09 EST
(In reply to Marc-Andre Laperle from comment #23)
> Could someone backport this to 4.5? I would do it but I am not the author of
> the original patch or a committer so I can't push it to gerrit :) It will be
> a good fix for SWTBot too.

Pushed the patch to R4_5_maintenance branch via http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/?h=R4_5_maintenance&id=a7bc9ddae7b09350e5d1aae1fce1a716bff1161f

Today's M-build should have the fix.
Comment 25 Marc-André Laperle CLA 2016-01-07 15:40:05 EST
(In reply to Arun Thondapu from comment #24)
> (In reply to Marc-Andre Laperle from comment #23)
> > Could someone backport this to 4.5? I would do it but I am not the author of
> > the original patch or a committer so I can't push it to gerrit :) It will be
> > a good fix for SWTBot too.
> 
> Pushed the patch to R4_5_maintenance branch via
> http://git.eclipse.org/c/platform/eclipse.platform.swt.git/commit/
> ?h=R4_5_maintenance&id=a7bc9ddae7b09350e5d1aae1fce1a716bff1161f
> 
> Today's M-build should have the fix.

I tested it and it works. Many thanks!
Comment 26 Arun Thondapu CLA 2016-01-12 02:28:21 EST
Resolving as it is fixed now in 4.5.2 but the backport to 4.4.2+ is still pending.
Comment 27 Markus Keller CLA 2016-02-04 13:53:17 EST
Verified in M20160203-1000.
Comment 28 Dani Megert CLA 2016-03-21 05:15:54 EDT
*** Bug 476169 has been marked as a duplicate of this bug. ***