Bug 546490: [GTK] Incorrect Table/Tree size

Address Tree sizing issues. The majority of the issues
stem from the fact that GTK reports a 1x1 size for
Widgets which are not visible. This afflicts columns
in Trees/Tables, and throws of computeSize() values.

This patch addresses this by initially setting the column
buttons visible whenever doing a pack() or computeSize()
operation.

Further more, GtkScrolledWindows without scrollbars
sometimes do not change their size, likely due to
caching. In order to work around, we check if the Tree
has an initial computed height equalling the header
height, and bump that height by 1px to trigger a resize.

Tested on GTK3.24 on X11 and Wayland. No AllNonBrowser
JUnit tests fail.

Change-Id: I7e6bc4940e9b026a30b81e1993ab09c7d5332753
Signed-off-by: Eric Williams <ericwill@redhat.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java
index 77975e1..7145a59 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java
@@ -89,6 +89,8 @@
 	TreeItem currentItem;
 	ImageList imageList, headerImageList;
 	boolean firstCustomDraw;
+	/** True iff computeSize has never been called on this Tree */
+	boolean firstCompute = true;
 	boolean modelChanged;
 	boolean expandAll;
 	int drawState, drawFlags;
@@ -600,9 +602,20 @@
 	checkWidget ();
 	if (wHint != SWT.DEFAULT && wHint < 0) wHint = 0;
 	if (hHint != SWT.DEFAULT && hHint < 0) hHint = 0;
+	/*
+	 * Set all the TreeColumn buttons visible otherwise
+	 * gtk_widget_get_preferred_size() will not take their size
+	 * into account.
+	 */
+	if (firstCompute) {
+		for (int x = 0; x < columns.length; x++) {
+			TreeColumn column = columns[x];
+			if (column != null) GTK.gtk_widget_set_visible(column.buttonHandle, true);
+		}
+		firstCompute = false;
+	}
 	GTK.gtk_widget_realize(handle);
 	Point size = computeNativeSize (handle, wHint, hHint, changed);
-	if (size.x == 0 && wHint == SWT.DEFAULT) size.x = DEFAULT_WIDTH;
 
 	/*
 	 * In GTK 3, computeNativeSize(..) sometimes just returns the header
@@ -616,14 +629,21 @@
 		size.y = getItemCount() * getItemHeightInPixels() + getHeaderHeight();
 	}
 
-	/*
-	 * In case the table doesn't contain any elements,
-	 * getItemCount returns 0 and size.y will be 0
-	 * so need to assign default height
-	 */
-	if (size.y == 0 && hHint == SWT.DEFAULT) size.y = DEFAULT_HEIGHT;
 	Rectangle trim = computeTrimInPixels (0, 0, size.x, size.y);
 	size.x = trim.width;
+	/*
+	 * Feature in GTK: sometimes GtkScrolledWindow's with no scrollbars
+	 * won't automatically adjust their size. This happens when a Tree
+	 * has a header, and the initial computed height was the height of
+	 * the of the header.
+	 *
+	 *  The fix is to increment the height by 1 in order to force a size
+	 *  update for the parent GtkScrollWindow, otherwise the headers
+	 *  will not be shown. This only happens once, see bug 546490.
+	 */
+	if (size.y == this.headerHeight && this.headerVisible && (style & SWT.NO_SCROLL) != 0) {
+		trim.height = trim.height + 1;
+	}
 	size.y = trim.height;
 	return size;
 }
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TreeColumn.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TreeColumn.java
index 42b7185..ec30bbe 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TreeColumn.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TreeColumn.java
@@ -447,6 +447,12 @@
 	int width = 0;
 	if (buttonHandle != 0) {
 		GtkRequisition requisition = new GtkRequisition ();
+		/*
+		 * Check if the header button is hidden, otherwise GTK will
+		 * return a 1x1 size. See bug 546490.
+		 */
+		boolean visible = GTK.gtk_widget_get_visible(buttonHandle);
+		if (!visible) GTK.gtk_widget_set_visible(buttonHandle, !visible);
 		gtk_widget_get_preferred_size (buttonHandle, requisition);
 		width = requisition.width;
 	}
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546490_TreeSizingIssues.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546490_TreeSizingIssues.java
new file mode 100644
index 0000000..90a69c6
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546490_TreeSizingIssues.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Patrick Tasse and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     Patrick Tasse - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.tests.gtk.snippets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.layout.RowLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+
+public class Bug546490_TreeSizingIssues {
+
+	private static final int NUM_COL = 5;
+	private static final int NUM_ROW = 5;
+
+	public static void main(String[] args) {
+		Display display = new Display();
+		Shell shell = new Shell(display);
+
+		shell.setLayout(new RowLayout(SWT.VERTICAL));
+
+		Label label1 = new Label(shell, SWT.NONE);
+		label1.setText("Tree #1 with no items, 5 columns packed");
+		Tree tree1 = new Tree(shell, SWT.NO_SCROLL);
+		tree1.setBackground(display.getSystemColor(SWT.COLOR_YELLOW));
+		tree1.setHeaderVisible(true);
+		tree1.setLinesVisible(true);
+		for (int col = 0; col < NUM_COL; col++) {
+			TreeColumn column = new TreeColumn(tree1, SWT.CENTER);
+			column.setText("Column " + col);
+			column.pack();
+		}
+
+		Label label2 = new Label(shell, SWT.NONE);
+		label2.setText("Tree #2 with no items, 5 columns width=0");
+		Tree tree2 = new Tree(shell, SWT.NO_SCROLL);
+		tree2.setBackground(display.getSystemColor(SWT.COLOR_YELLOW));
+		tree2.setHeaderVisible(true);
+		tree2.setLinesVisible(true);
+		for (int col = 0; col < NUM_COL; col++) {
+			TreeColumn column = new TreeColumn(tree2, SWT.CENTER);
+			column.setText("Column " + col);
+			column.setWidth(0);
+		}
+
+		Label label3 = new Label(shell, SWT.NONE);
+		label3.setText("Tree #3 with no items, 5 columns width=100");
+		Tree tree3 = new Tree(shell, SWT.NO_SCROLL);
+		tree3.setBackground(display.getSystemColor(SWT.COLOR_YELLOW));
+		tree3.setHeaderVisible(true);
+		tree3.setLinesVisible(true);
+		for (int col = 0; col < NUM_COL; col++) {
+			TreeColumn column = new TreeColumn(tree3, SWT.CENTER);
+			column.setText("Column " + col);
+			column.setWidth(100);
+		}
+
+		Label label4 = new Label(shell, SWT.NONE);
+		label4.setText("Tree #4 with 5 items, 5 columns width=100");
+		Tree tree4 = new Tree(shell, SWT.NO_SCROLL);
+		tree4.setBackground(display.getSystemColor(SWT.COLOR_YELLOW));
+		tree4.setHeaderVisible(true);
+		tree4.setLinesVisible(true);
+		for (int col = 0; col < NUM_COL; col++) {
+			TreeColumn column = new TreeColumn(tree4, SWT.CENTER);
+			column.setText("Column " + col);
+			column.setWidth(100);
+		}
+		for (int row = 1; row <= NUM_ROW; row++) {
+			TreeItem item = new TreeItem(tree4, SWT.NONE);
+			if (row % 2 == 0) {
+				item.setBackground(display.getSystemColor(SWT.COLOR_CYAN));
+			} else {
+				item.setBackground(display.getSystemColor(SWT.COLOR_GREEN));
+			}
+			for (int col = 0; col < NUM_COL; col++) {
+				item.setText(col, "R" + row + "C" + col);
+			}
+		}
+
+		Label label5 = new Label(shell, SWT.NONE);
+		label5.setText("Tree #5 with 5 items, 5 columns packed");
+		Tree tree5 = new Tree(shell, SWT.NO_SCROLL);
+		tree5.setBackground(display.getSystemColor(SWT.COLOR_YELLOW));
+		tree5.setHeaderVisible(true);
+		tree5.setLinesVisible(true);
+		for (int col = 0; col < NUM_COL; col++) {
+			TreeColumn column = new TreeColumn(tree5, SWT.CENTER);
+			column.setText("Column " + col);
+		}
+		for (int row = 1; row <= NUM_ROW; row++) {
+			TreeItem item = new TreeItem(tree5, SWT.NONE);
+			if (row % 2 == 0) {
+				item.setBackground(display.getSystemColor(SWT.COLOR_CYAN));
+			} else {
+				item.setBackground(display.getSystemColor(SWT.COLOR_GREEN));
+			}
+			for (int col = 0; col < NUM_COL; col++) {
+				item.setText(col, "R" + row + "C" + col);
+			}
+		}
+		for (TreeColumn column : tree5.getColumns()) {
+			column.pack();
+		}
+
+		Label label = new Label(shell, SWT.NONE);
+		label.setText("Resize shell to see tree sizes change!");
+
+		shell.setText("Tree, never resized");
+		shell.pack();
+		shell.open();
+		shell.addControlListener(new ControlAdapter() {
+			@Override
+			public void controlResized(ControlEvent e) {
+				shell.setText("Tree, has been resized");
+			}
+		});
+		while (!shell.isDisposed()) {
+			if (!display.readAndDispatch()) {
+				display.sleep();
+			}
+		}
+		display.dispose();
+	}
+}
\ No newline at end of file