Bug 531048 [GTK3] Large problems drawing ownerdraw tables (fix)

TL;DR:
Gtk3 delays some Tree/Table initialization logic.
We wait till it's done first to finish some initialization after.
It's not a clean fix, but given SWT's custom drawing and requirement
for API to be win/cocoa consistent, I couldn't find a better fix.


Details:
Gtk3's delayed initialization breaks custom drawn Tree/Tables that have
invisible columns
because internally GTK skips a lot of initialization for invisible
items (for optimization).

Fix is to wait till this is done and in the mean time 'cache' the
'desired' state of a column in a hash table. Once initialization is
done, we flush state (i.e hide/show columns as requested).

Technical notes:
- Fix is same for Tree and Table.
- I put things into Control, because I have another fix in mind that
  will use the 'delayed' logic. (invisible Rowlayout had such issues).
- I piggy back onto 'draw' signal, which is only sent once
  Gtk3/Caching initialization has occured.
- I had to put columns into a hash table because some columns
  don't have a TableColumn java object associated with it.

On the side, this also fixes accessibility warning reported in 399522.

Verified against bug Snippet, jUnits, manual tests, child eclipse.

@ Reviewer, you can verify against snippet found in bug.
Before you get cheese, after thinngs work.

Patchset 4:
- Minor update, moved some code higher up into table/tree
so that check is only done for these two widgets and not for all
widgets.

Bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=5310483
Change-Id: I3152f64ddb296879d9bad08bdaeb5c38e0672ef8
Signed-off-by: Leo Ufimtsev <lufimtse@redhat.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java
index 2cddd0a..cab6ca3 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GTK.java
@@ -7772,8 +7772,13 @@
 			lock.unlock();
 		}
 	}
+
 	/** @param column cast=(GtkTreeViewColumn *) */
 	public static final native boolean _gtk_tree_view_column_get_visible(long /*int*/ column);
+	/**
+	 * (!) SWT: This method should not be called directly.
+	 * Instead use Control.gtk_tree_view_column_get_visible (...)
+	 */
 	public static final boolean gtk_tree_view_column_get_visible(long /*int*/ column) {
 		lock.lock();
 		try {
@@ -7782,6 +7787,7 @@
 			lock.unlock();
 		}
 	}
+
 	/** @param column cast=(GtkTreeViewColumn *) */
 	public static final native int _gtk_tree_view_column_get_width(long /*int*/ column);
 	public static final int gtk_tree_view_column_get_width(long /*int*/ column) {
@@ -7959,8 +7965,13 @@
 			lock.unlock();
 		}
 	}
+
 	/** @param tree_column cast=(GtkTreeViewColumn *) */
 	public static final native void _gtk_tree_view_column_set_visible (long /*int*/ tree_column, boolean visible);
+	/**
+	 * (!) SWT: This method should not be called directly.
+	 * Instead use Control.gtk_tree_view_column_set_visible (...)
+	 */
 	public static final void gtk_tree_view_column_set_visible (long /*int*/ tree_column, boolean visible) {
 		lock.lock();
 		try {
@@ -7970,6 +7981,7 @@
 		}
 	}
 	/**
+
 	 * @param tree_column cast=(GtkTreeViewColumn *)
 	 * @param widget cast=(GtkWidget *)
 	 */
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
index 22308d0..7971ff6 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
@@ -93,6 +93,23 @@
 		if (gestureEnd.getAddress() == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
 	}
 
+	/**
+	 * (Gtk3-only) Delayed initialization after Gtk3 lazy initialization/caching occurred.
+	 *
+	 * 1) On Gtk3, GtkTree is heavily optimized and a lot of things are cached/initialized later (e.g after 5th/10th
+	 * g_main_context_iteration(), or during idle CPU time).
+	 *
+	 * 2) Further, Gtk3.6+ (ish) is optimized not to initialize 'invisible' components (e.g invisible table columns).
+	 *
+	 * Due to this lazy (1) & ignored code (2) combination, if a *custom* component is invisible during the lazy initialization,
+	 * it can lead to incorrect initialization of such custom components (e.g Custom-drawn Virtual trees/tables).
+	 * E.g 'TreeCheese' (see Screenshots in Bug 531048).
+	 *
+	 * The solution is to finalize some initialization *after* the lazy initialization is completed.
+	 */
+	boolean lazyInitializationOccured;
+	Hashtable<Long, Boolean> delayedVisibilityState = new Hashtable<>();
+
 Control () {
 }
 
@@ -6379,4 +6396,73 @@
 
 	return new Point (x [0], y [0]);
 }
+
+/**
+* GtkTreeViewColumns must be visible during gtk3's lazy initialization/caching,
+* otherwise custom-drawing/renders aren't initialized properly and we
+* get tree-cheese. See 531048.
+*
+* The solution is to cache the 'desired' visibility state during initialization,
+* and only apply it after lazy initialization is complete.
+*
+* Note on TableColumn Visibility:
+* 1) When a (Java) Table is created, it creates a GtkTreeViewColumn which is visible. (Note, no Java TableColumn is created)
+* 2) When the first (Java) TableColum is created, the first GtkTreeViewColumn is attached to it and is made invisible.
+* 3) When the 2nd+ (Java) TableColumn is created, a new GtkTreeViewColumn is created for each one and is made invisible.
+*
+* TableColumn is invisible until pack() or setWidth() is called on it, this is so that there is consistent api across Win/Cocoa/Gtk.
+* See: org.eclipse.swt.tests.manualJUnit.MJ_Table: column_noWidth_bug399522()
+*/
+void gtk_tree_view_column_set_visible (long /*int*/ columnHandle, boolean visible) {
+	if (GTK.GTK3) {
+		if (lazyInitializationOccured) {
+			GTK.gtk_tree_view_column_set_visible (columnHandle, visible);
+		} else {
+			delayedVisibilityState.put(new Long(columnHandle), Boolean.valueOf(visible));
+		}
+	} else {
+		GTK.gtk_tree_view_column_set_visible (columnHandle, visible);
+	}
+}
+
+boolean gtk_tree_view_column_get_visible (long /*int*/ columnHandle) {
+	if (GTK.GTK3) {
+		if (lazyInitializationOccured) {
+			return GTK.gtk_tree_view_column_get_visible(columnHandle);
+		} else {
+			Boolean visibilityState = delayedVisibilityState.get(new Long(columnHandle));
+			if (visibilityState != null) {
+				return visibilityState;
+			} else {
+				return true; //GtkTreeColumn is initially visible until we hide it.
+			}
+		}
+	} else {
+		return GTK.gtk_tree_view_column_get_visible(columnHandle);
+	}
+}
+
+
+/**
+ * From testing, I observed that generally the 'draw' signal is only sent once lazy
+ * initialization/caching is complete, so we piggy back onto the draw signal for delayed initialization.
+ * In contrast, mapping/realization events can sometimes be sent before such 'lazy' initialization is completed (or during),
+ * so they are not suitable.
+ * I.e mapping/realization events can be sent before the first g_main_context_iteration() is ran, but draw is only sent
+ *   *just before* something is actually visually displayed to the user. (typically after 16+ g_main_context_iterations).
+ *
+ * See bug 531048.
+ */
+void delayedInitialization(long /*int*/ widget) {
+	assert GTK.GTK3;
+	if (isDisposed()) return;
+
+	for (Long columnHandleObject : delayedVisibilityState.keySet()) {
+		long /*int*/ columnHandle = (long /*int*/) columnHandleObject.longValue();
+		Boolean visible  = delayedVisibilityState.get(columnHandleObject);
+		if (visible != null) {
+			GTK.gtk_tree_view_column_set_visible (columnHandle, visible);
+		}
+	}
+}
 }
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java
index c572e51..a64bdfc 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java
@@ -623,12 +623,7 @@
 	GTK.gtk_tree_view_column_set_clickable (columnHandle, true);
 	GTK.gtk_tree_view_column_set_min_width (columnHandle, 0);
 	GTK.gtk_tree_view_insert_column (handle, columnHandle, index);
-	/*
-	* Bug in GTK3.  The column header has the wrong CSS styling if it is hidden
-	* when inserting to the tree widget.  The fix is to hide the column only
-	* after it is inserted.
-	*/
-	if (columnCount != 0) GTK.gtk_tree_view_column_set_visible (columnHandle, false);
+
 	if (column != null) {
 		column.handle = columnHandle;
 		column.modelIndex = modelIndex;
@@ -685,10 +680,13 @@
 
 void createItem (TableColumn column, int index) {
 	if (!(0 <= index && index <= columnCount)) error (SWT.ERROR_INVALID_RANGE);
+
+	// A GtkColumn that is not a (java)TableColumn is created when Table is created.
+	// - For the first TableColumn java object, we attach the first created GtkColumn to the (java)TableColumn object.
+	// - For every subsequent TableColumn java object, we create a new column.
 	if (columnCount == 0) {
 		column.handle = GTK.gtk_tree_view_get_column (handle, 0);
 		GTK.gtk_tree_view_column_set_sizing (column.handle, GTK.GTK_TREE_VIEW_COLUMN_FIXED);
-		GTK.gtk_tree_view_column_set_visible (column.handle, false);
 		column.modelIndex = FIRST_COLUMN;
 		createRenderers (column.handle, column.modelIndex, true, column.style);
 		column.customDraw = firstCustomDraw;
@@ -696,6 +694,13 @@
 	} else {
 		createColumn (column, index);
 	}
+	/*
+	* Bug in GTK3.  The column header has the wrong CSS styling if it is hidden
+	* when inserting to the tree widget.  The fix is to hide the column only
+	* after it is inserted.
+	* Bug 393729
+	*/
+	gtk_tree_view_column_set_visible(column.handle, false);
 	long /*int*/ boxHandle = gtk_box_new (GTK.GTK_ORIENTATION_HORIZONTAL, false, 3);
 	if (boxHandle == 0) error (SWT.ERROR_NO_HANDLES);
 	long /*int*/ labelHandle = GTK.gtk_label_new_with_mnemonic (null);
@@ -1106,7 +1111,7 @@
 		}
 		GTK.gtk_tree_view_set_model (handle, newModel);
 		setModel (newModel);
-		createColumn (null, 0);
+		createColumn (null, 0); // Reached when disposing last TableColumn java Object. Created so a column would exist without a TableColumn java object.
 	} else {
 		for (int i=0; i<itemCount; i++) {
 			TableItem item = items [i];
@@ -2278,6 +2283,10 @@
 
 @Override
 long /*int*/ gtk_draw (long /*int*/ widget, long /*int*/ cairo) {
+	if (GTK.GTK3 && !lazyInitializationOccured) {
+		lazyInitializationOccured = true;
+		delayedInitialization(handle);
+	}
 	if ((state & OBSCURED) != 0) return 0;
 	drawInheritedBackground (0, cairo);
 	return super.gtk_draw (widget, cairo);
@@ -2355,7 +2364,7 @@
 	boolean fixVisible = columns != 0;
 	while (list != 0) {
 		long /*int*/ column = OS.g_list_data (list);
-		if (GTK.gtk_tree_view_column_get_visible (column)) {
+		if (gtk_tree_view_column_get_visible (column)) {
 			fixVisible = false;
 			break;
 		}
@@ -2364,18 +2373,18 @@
 	long /*int*/ columnHandle = 0;
 	if (fixVisible) {
 		columnHandle = OS.g_list_data (columns);
-		GTK.gtk_tree_view_column_set_visible (columnHandle, true);
+		gtk_tree_view_column_set_visible (columnHandle, true);
 	}
 	super.gtk_widget_size_request (widget, requisition);
 	if (fixVisible) {
-		GTK.gtk_tree_view_column_set_visible (columnHandle, false);
+		gtk_tree_view_column_set_visible (columnHandle, false);
 	}
 	if (columns != 0) OS.g_list_free (columns);
 }
 
 void hideFirstColumn () {
 	long /*int*/ firstColumn = GTK.gtk_tree_view_get_column (handle, 0);
-	GTK.gtk_tree_view_column_set_visible (firstColumn, false);
+	gtk_tree_view_column_set_visible (firstColumn, false);
 }
 
 @Override
@@ -4072,10 +4081,10 @@
 	int columnCount = Math.max (1, this.columnCount);
 	for (int i=0; i<columnCount; i++) {
 		long /*int*/ column = GTK.gtk_tree_view_get_column (handle, i);
-		if (GTK.gtk_tree_view_column_get_visible (column)) return false;
+		if (gtk_tree_view_column_get_visible (column)) return false;
 	}
 	long /*int*/ firstColumn = GTK.gtk_tree_view_get_column (handle, 0);
-	GTK.gtk_tree_view_column_set_visible (firstColumn, true);
+	gtk_tree_view_column_set_visible (firstColumn, true);
 	return true;
 }
 
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TableColumn.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TableColumn.java
index 84b8fcc..a092fc8 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TableColumn.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TableColumn.java
@@ -202,6 +202,7 @@
 
 @Override
 void deregister() {
+	parent.gtk_tree_view_column_set_visible(this.handle, true); // Bug 399522. Stop Acessibiliity throwing a critical warning due to column being invisible.
 	super.deregister ();
 	display.removeWidget (handle);
 	if (buttonHandle != 0) display.removeWidget (buttonHandle);
@@ -326,7 +327,7 @@
 
 int getWidthInPixels () {
 	checkWidget();
-	if (!GTK.gtk_tree_view_column_get_visible (handle)) {
+	if (!parent.gtk_tree_view_column_get_visible (handle)) {
 		return 0;
 	}
 	if (useFixedWidth) return GTK.gtk_tree_view_column_get_fixed_width (handle);
@@ -715,18 +716,20 @@
 void setWidthInPixels (int width) {
 	checkWidget();
 	if (width < 0) return;
-	if (width == lastWidth) return;
-	if (width > 0) {
-		useFixedWidth = true;
-		GTK.gtk_tree_view_column_set_fixed_width (handle, width);
-	}
+
 	/*
 	 * Bug in GTK.  For some reason, calling gtk_tree_view_column_set_visible()
 	 * when the parent is not realized fails to show the column. The fix is to
 	 * ensure that the table has been realized.
 	 */
 	if (width != 0) GTK.gtk_widget_realize (parent.handle);
-	GTK.gtk_tree_view_column_set_visible (handle, width != 0);
+	parent.gtk_tree_view_column_set_visible(this.handle, width != 0);
+
+	if (width == lastWidth) return;
+	if (width > 0) {
+		useFixedWidth = true;
+		GTK.gtk_tree_view_column_set_fixed_width (handle, width);
+	}
 	lastWidth = width;
 	/*
 	 * Bug in GTK. When the column is made visible the event window of column
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TableItem.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TableItem.java
index f904159..a1d3b89 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TableItem.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TableItem.java
@@ -359,7 +359,7 @@
 			rect.width = Math.max (0, right - rect.x);
 		}
 	}
-	int width = GTK.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
+	int width = parent.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
 	Rectangle r = new Rectangle (rect.x, rect.y, width, rect.height + 1);
 	if (parent.getHeaderVisible() && GTK.GTK_VERSION > OS.VERSION(3, 9, 0)) {
 		r.y += parent.getHeaderHeightInPixels();
@@ -431,7 +431,7 @@
 		rect.x += x [0] + w [0];
 		rect.width -= x [0] + w [0];
 	}
-	int width = GTK.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
+	int width = parent.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
 	Rectangle r = new Rectangle (rect.x, rect.y, width, rect.height + 1);
 	return r;
 }
@@ -646,7 +646,7 @@
 		rect.x += x [0];
 	}
 	rect.width = w [0];
-	int width = GTK.gtk_tree_view_column_get_visible (column) ? rect.width : 0;
+	int width = parent.gtk_tree_view_column_get_visible (column) ? rect.width : 0;
 	return new Rectangle (rect.x, rect.y, width, rect.height + 1);
 }
 
@@ -814,7 +814,7 @@
 			rect.width = Math.max (0, right - rect.x);
 		}
 	}
-	int width = GTK.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
+	int width = parent.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
 	return new Rectangle (rect.x, rect.y, width, rect.height + 1);
 }
 
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 50de17c..6644346 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
@@ -726,12 +726,7 @@
 	GTK.gtk_tree_view_column_set_clickable (columnHandle, true);
 	GTK.gtk_tree_view_column_set_min_width (columnHandle, 0);
 	GTK.gtk_tree_view_insert_column (handle, columnHandle, index);
-	/*
-	* Bug in GTK3.  The column header has the wrong CSS styling if it is hidden
-	* when inserting to the tree widget.  The fix is to hide the column only
-	* after it is inserted.
-	*/
-	if (columnCount != 0) GTK.gtk_tree_view_column_set_visible (columnHandle, false);
+
 	if (column != null) {
 		column.handle = columnHandle;
 		column.modelIndex = modelIndex;
@@ -801,7 +796,6 @@
 	if (columnCount == 0) {
 		column.handle = GTK.gtk_tree_view_get_column (handle, 0);
 		GTK.gtk_tree_view_column_set_sizing (column.handle, GTK.GTK_TREE_VIEW_COLUMN_FIXED);
-		GTK.gtk_tree_view_column_set_visible (column.handle, false);
 		column.modelIndex = FIRST_COLUMN;
 		createRenderers (column.handle, column.modelIndex, true, column.style);
 		column.customDraw = firstCustomDraw;
@@ -809,6 +803,12 @@
 	} else {
 		createColumn (column, index);
 	}
+	/*
+	* Bug in GTK3.  The column header has the wrong CSS styling if it is hidden
+	* when inserting to the tree widget.  The fix is to hide the column only
+	* after it is inserted. Bug 393729.
+	*/
+	gtk_tree_view_column_set_visible (column.handle, false);
 	long /*int*/ boxHandle = gtk_box_new (GTK.GTK_ORIENTATION_HORIZONTAL, false, 3);
 	if (boxHandle == 0) error (SWT.ERROR_NO_HANDLES);
 	long /*int*/ labelHandle = GTK.gtk_label_new_with_mnemonic (null);
@@ -2311,6 +2311,10 @@
 
 @Override
 long /*int*/ gtk_draw (long /*int*/ widget, long /*int*/ cairo) {
+	if (GTK.GTK3 && !lazyInitializationOccured) {
+		lazyInitializationOccured = true;
+		delayedInitialization(handle);
+	}
 	if ((state & OBSCURED) != 0) return 0;
 	drawInheritedBackground	(0, cairo);
 	return super.gtk_draw (widget, cairo);
@@ -2500,7 +2504,7 @@
 	boolean fixVisible = columns != 0;
 	while (list != 0) {
 		long /*int*/ column = OS.g_list_data (list);
-		if (GTK.gtk_tree_view_column_get_visible (column)) {
+		if (gtk_tree_view_column_get_visible (column)) {
 			fixVisible = false;
 			break;
 		}
@@ -2509,18 +2513,18 @@
 	long /*int*/ columnHandle = 0;
 	if (fixVisible) {
 		columnHandle = OS.g_list_data (columns);
-		GTK.gtk_tree_view_column_set_visible (columnHandle, true);
+		gtk_tree_view_column_set_visible (columnHandle, true);
 	}
 	super.gtk_widget_size_request (widget, requisition);
 	if (fixVisible) {
-		GTK.gtk_tree_view_column_set_visible (columnHandle, false);
+		gtk_tree_view_column_set_visible (columnHandle, false);
 	}
 	if (columns != 0) OS.g_list_free (columns);
 }
 
 void hideFirstColumn () {
 	long /*int*/ firstColumn = GTK.gtk_tree_view_get_column (handle, 0);
-	GTK.gtk_tree_view_column_set_visible (firstColumn, false);
+	gtk_tree_view_column_set_visible (firstColumn, false);
 }
 
 @Override
@@ -3962,10 +3966,10 @@
 	int columnCount = Math.max (1, this.columnCount);
 	for (int i=0; i<columnCount; i++) {
 		long /*int*/ column = GTK.gtk_tree_view_get_column (handle, i);
-		if (GTK.gtk_tree_view_column_get_visible (column)) return false;
+		if (gtk_tree_view_column_get_visible (column)) return false;
 	}
 	long /*int*/ firstColumn = GTK.gtk_tree_view_get_column (handle, 0);
-	GTK.gtk_tree_view_column_set_visible (firstColumn, true);
+	gtk_tree_view_column_set_visible (firstColumn, true);
 	return true;
 }
 
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 811a73d..470e9fa 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
@@ -204,6 +204,7 @@
 
 @Override
 void deregister() {
+	parent.gtk_tree_view_column_set_visible(this.handle, true); // Bug 399522. Stop Acessibiliity throwing a critical warning due to column being invisible.
 	super.deregister ();
 	display.removeWidget (handle);
 	if (buttonHandle != 0) display.removeWidget (buttonHandle);
@@ -328,7 +329,7 @@
 
 int getWidthInPixels () {
 	checkWidget();
-	if (!GTK.gtk_tree_view_column_get_visible (handle)) {
+	if (!parent.gtk_tree_view_column_get_visible (handle)) {
 		return 0;
 	}
 	if (useFixedWidth) return GTK.gtk_tree_view_column_get_fixed_width (handle);
@@ -701,18 +702,18 @@
 void setWidthInPixels (int width) {
 	checkWidget();
 	if (width < 0) return;
-	if (width == lastWidth) return;
-	if (width > 0) {
-		useFixedWidth = true;
-		GTK.gtk_tree_view_column_set_fixed_width (handle, width);
-	}
 	/*
 	 * Bug in GTK.  For some reason, calling gtk_tree_view_column_set_visible()
 	 * when the parent is not realized fails to show the column. The fix is to
 	 * ensure that the table has been realized.
 	 */
 	if (width != 0) GTK.gtk_widget_realize (parent.handle);
-	GTK.gtk_tree_view_column_set_visible (handle, width != 0);
+	parent.gtk_tree_view_column_set_visible (handle, width != 0);
+	if (width == lastWidth) return;
+	if (width > 0) {
+		useFixedWidth = true;
+		GTK.gtk_tree_view_column_set_fixed_width (handle, width);
+	}
 	lastWidth = width;
 	/*
 	 * Bug in GTK. When the column is made visible the event window of column
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TreeItem.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TreeItem.java
index 802a1f9..03b847c 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TreeItem.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TreeItem.java
@@ -481,7 +481,7 @@
 		rect.x += x [0] + w [0];
 		rect.width -= x [0] + w [0];
 	}
-	int width = GTK.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
+	int width = parent.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
 	Rectangle r = new Rectangle (rect.x, rect.y, width, rect.height + 1);
 	return r;
 }
@@ -545,7 +545,7 @@
 			rect.width = Math.max (0, right - rect.x);
 		}
 	}
-	int width = GTK.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
+	int width = parent.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
 	Rectangle r = new Rectangle (rect.x, rect.y, width, rect.height + 1);
 	if (parent.getHeaderVisible() && GTK.GTK_VERSION > OS.VERSION(3, 9, 0)) {
 		r.y += parent.getHeaderHeightInPixels();
@@ -791,7 +791,7 @@
 		rect.x += x [0];
 	}
 	rect.width = w [0];
-	int width = GTK.gtk_tree_view_column_get_visible (column) ? rect.width : 0;
+	int width = parent.gtk_tree_view_column_get_visible (column) ? rect.width : 0;
 	return new Rectangle (rect.x, rect.y, width, rect.height + 1);
 }
 
@@ -1033,7 +1033,7 @@
 			rect.width = Math.max (0, right - rect.x);
 		}
 	}
-	int width = GTK.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
+	int width = parent.gtk_tree_view_column_get_visible (column) ? rect.width + 1 : 0;
 	return new Rectangle (rect.x, rect.y, width, rect.height + 1);
 }