7c442c1
From 1a3294ba5966b01cc2953d4ad12ed02eb971b97f Mon Sep 17 00:00:00 2001
7c442c1
From: Leo Ufimtsev
7c442c1
Date: Wed, 14 Feb 2018 10:49:01 -0500
7c442c1
Subject: Bug 510803 [GTK3] Regression in table editing capabilities in
7c442c1
 tabfolder.
7c442c1
7c442c1
Breakage occurred because tabItem reparented an item that had a
7c442c1
non-standard gDk parent window.
7c442c1
7c442c1
Solution: fix gdk window parent for such special controls.
7c442c1
(I.e ControlEditors in tables).
7c442c1
7c442c1
Verification:
7c442c1
- Open child eclipse, change method signature.
7c442c1
  Now table cells can be edited via click.
7c442c1
- Open attached snippet, with patch cells can be edited properly.
7c442c1
- AllTests Gtk3.22
7c442c1
- X11/Wayland.
7c442c1
7c442c1
Patchset 3:
7c442c1
- Minor rename of methods to clarify that it's a *gdk* window,
7c442c1
7c442c1
Bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=5108033
7c442c1
Change-Id: I8dcaac950eb0847dd97016b2140c607012550d2f
7c442c1
Signed-off-by: Leo Ufimtsev <lufimtse@redhat.com>
7c442c1
---
7c442c1
 .../Eclipse SWT PI/gtk/library/os.c                |   8 ++
7c442c1
 .../gtk/org/eclipse/swt/internal/gtk/OS.java      |   4 +
7c442c1
 .../gtk/org/eclipse/swt/widgets/Composite.java     |  10 ++
7c442c1
 .../gtk/org/eclipse/swt/widgets/Control.java       |  51 ++++++++-
7c442c1
 .../gtk/org/eclipse/swt/widgets/ExpandItem.java    |   2 +-
7c442c1
 .../gtk/org/eclipse/swt/widgets/TabItem.java       |   4 +-
7c442c1
 .../gtk/org/eclipse/swt/widgets/Table.java         |   6 +-
7c442c1
 .../gtk/org/eclipse/swt/widgets/Tree.java          |   6 +-
7c442c1
 .../gtk/org/eclipse/swt/widgets/Widget.java        |  15 ---
7c442c1
 .../Bug510803_TabFolder_Table_inPlaceEditing.java  | 108 ------------------
7c442c1
 .../Bug510803_TabFolder_TreeEditor_Regression.java | 124 +++++++++++++++++++++
7c442c1
 11 files changed, 203 insertions(+), 135 deletions(-)
7c442c1
 delete mode 100644 tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug510803_TabFolder_Table_inPlaceEditing.java
7c442c1
 create mode 100644 tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug510803_TabFolder_TreeEditor_Regression.java
7c442c1
7c442c1
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
7c442c1
index bf5de70..428d448 100644
7c442c1
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c	
7c442c1
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c	
7c442c1
@@ -16764,7 +16764,15 @@ JNIEXPORT void JNICALL OS_NATIVE(_1gtk_1widget_1reparent)
7c442c1
 	(JNIEnv *env, jclass that, jintLong arg0, jintLong arg1)
7c442c1
 {
7c442c1
 	OS_NATIVE_ENTER(env, that, _1gtk_1widget_1reparent_FUNC);
7c442c1
+/*
7c442c1
 	gtk_widget_reparent((GtkWidget *)arg0, (GtkWidget *)arg1);
7c442c1
+*/
7c442c1
+	{
7c442c1
+		OS_LOAD_FUNCTION(fp, gtk_widget_reparent)
7c442c1
+		if (fp) {
7c442c1
+			((void (CALLING_CONVENTION*)(GtkWidget *, GtkWidget *))fp)((GtkWidget *)arg0, (GtkWidget *)arg1);
7c442c1
+		}
7c442c1
+	}
7c442c1
 	OS_NATIVE_EXIT(env, that, _1gtk_1widget_1reparent_FUNC);
7c442c1
 }
7c442c1
 #endif
7c442c1
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Composite.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Composite.java
7c442c1
index 2619114..57bbf52 100644
7c442c1
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Composite.java	
7c442c1
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Composite.java	
7c442c1
@@ -506,6 +506,16 @@ void fixChildren (Shell newShell, Shell oldShell, Decorations newDecorations, De
7c442c1
 }
7c442c1
 
7c442c1
 @Override
7c442c1
+void fixParentGdkWindow() {
7c442c1
+	assert OS.GTK3;
7c442c1
+	// Changes to this method should be verified via
7c442c1
+	// org.eclipse.swt.tests.gtk/*/Bug510803_TabFolder_TreeEditor_Regression.java (part two)
7c442c1
+	for (Control child : _getChildren()) {
7c442c1
+		child.fixParentGdkWindow();
7c442c1
+	}
7c442c1
+}
7c442c1
+
7c442c1
+@Override
7c442c1
 void fixModal(long /*int*/ group, long /*int*/ modalGroup)  {
7c442c1
 	Control[] controls = _getChildren ();
7c442c1
 	for (int i = 0; i < controls.length; i++) {
7c442c1
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
7c442c1
index e29d144..b0768d5 100644
7c442c1
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java	
7c442c1
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java	
7c442c1
@@ -2656,6 +2656,51 @@ void fixChildren (Shell newShell, Shell oldShell, Decorations newDecorations, De
7c442c1
 	oldDecorations.fixDecorations (newDecorations, this, menus);
7c442c1
 }
7c442c1
 
7c442c1
+/**
7c442c1
+ * In some situations, a control has a non-standard parent GdkWindow (Note gDk, not gTk).
7c442c1
+ * E.g, an TreeEditor who's parent is a Tree should have the Tree Viewer's inner bin as parent window.
7c442c1
+ *
7c442c1
+ * Note, composites should treat this differently and take child controls into consideration.
7c442c1
+ */
7c442c1
+void fixParentGdkWindow() {
7c442c1
+	assert OS.GTK3;
7c442c1
+	// Changes to this method should be verified via
7c442c1
+	// org.eclipse.swt.tests.gtk/*/Bug510803_TabFolder_TreeEditor_Regression.java (part one)
7c442c1
+	parent.setParentGdkWindow(this);
7c442c1
+}
7c442c1
+
7c442c1
+/**
7c442c1
+ * Native gtkwidget re-parenting in SWT on Gtk3 needs to be handled in a special way because
7c442c1
+ * some controls have non-standard GdkWindow as parents. (E.g ControlEditors), and other controls
7c442c1
+ * like TabItem and ExpandBar use reparenting to preserve proper hierarchy for correct event traversal (like dnd).
7c442c1
+ *
7c442c1
+ * Note, GdkWindows != GtkWindows.
7c442c1
+ *
7c442c1
+ * You should never call gtk_widget_reparent() directly or reparent widgets outside this method,
7c442c1
+ * otherwise you can break TabItem/TreeEditors.
7c442c1
+ *
7c442c1
+ * @param control that should be reparented.
7c442c1
+ * @param newParentHandle pointer/handle to the new GtkWidget parent.
7c442c1
+ */
7c442c1
+static void gtk_widget_reparent (Control control, long /*int*/ newParentHandle) {
7c442c1
+	if (OS.GTK3) {
7c442c1
+		// Changes to this method should be verified via both parts in:
7c442c1
+		// org.eclipse.swt.tests.gtk/*/Bug510803_TabFolder_TreeEditor_Regression.java
7c442c1
+		long /*int*/ widget = control.topHandle();
7c442c1
+		long /*int*/ parentContainer = OS.gtk_widget_get_parent (widget);
7c442c1
+		assert parentContainer != 0 : "Improper use of Control.gtk_widget_reparent. Widget currently has no parent.";
7c442c1
+		if (parentContainer != 0) {
7c442c1
+			OS.g_object_ref (widget); //so that it won't get destroyed due to lack of references.
7c442c1
+			OS.gtk_container_remove (parentContainer, widget);
7c442c1
+			OS.gtk_container_add (newParentHandle, widget);
7c442c1
+			OS.g_object_unref (widget);
7c442c1
+			control.fixParentGdkWindow();
7c442c1
+		}
7c442c1
+	} else { // Gtk2.
7c442c1
+		OS.gtk_widget_reparent(control.topHandle(), newParentHandle);
7c442c1
+	}
7c442c1
+}
7c442c1
+
7c442c1
 @Override
7c442c1
 long /*int*/ fixedMapProc (long /*int*/ widget) {
7c442c1
 	OS.gtk_widget_set_mapped (widget, true);
7c442c1
@@ -5254,7 +5299,7 @@ public boolean setParent (Composite parent) {
7c442c1
 		oldDecorations.fixAccelGroup ();
7c442c1
 	}
7c442c1
 	long /*int*/ newParent = parent.parentingHandle();
7c442c1
-	OS.gtk_widget_reparent(topHandle, newParent);
7c442c1
+	gtk_widget_reparent(this, newParent);
7c442c1
 	if (OS.GTK3) {
7c442c1
 		OS.swt_fixed_move (newParent, topHandle, x, y);
7c442c1
 	} else {
7c442c1
@@ -5287,7 +5332,7 @@ void setParentBackground () {
7c442c1
 	if (fixedHandle != 0) setBackgroundColor (fixedHandle, null);
7c442c1
 }
7c442c1
 
7c442c1
-void setParentWindow (Control child) {
7c442c1
+void setParentGdkWindow (Control child) {
7c442c1
 }
7c442c1
 
7c442c1
 boolean setRadioSelection (boolean value) {
7c442c1
@@ -5697,7 +5742,7 @@ void showWidget () {
7c442c1
 	state |= ZERO_WIDTH | ZERO_HEIGHT;
7c442c1
 	long /*int*/ topHandle = topHandle ();
7c442c1
 	long /*int*/ parentHandle = parent.parentingHandle ();
7c442c1
-	parent.setParentWindow (this);
7c442c1
+	parent.setParentGdkWindow (this);
7c442c1
 	OS.gtk_container_add (parentHandle, topHandle);
7c442c1
 	if (handle != 0 && handle != topHandle) OS.gtk_widget_show (handle);
7c442c1
 	if ((state & (ZERO_WIDTH | ZERO_HEIGHT)) == 0) {
7c442c1
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ExpandItem.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ExpandItem.java
7c442c1
index fcfbd33..6e48823 100644
7c442c1
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ExpandItem.java	
7c442c1
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/ExpandItem.java	
7c442c1
@@ -525,7 +525,7 @@ public void setControl (Control control) {
7c442c1
 			//As ExpandItem's child can be created before the ExpandItem, our only
7c442c1
 			//option is to reparent the child upon the setControl(..) call.
7c442c1
 			//This is simmilar to TabFolder.
7c442c1
-			gtk_widget_reparent (control.topHandle (), clientHandle ());
7c442c1
+			Control.gtk_widget_reparent (control, clientHandle ());
7c442c1
 		}
7c442c1
 	}
7c442c1
 	parent.layoutItems (0, true);
7c442c1
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TabItem.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TabItem.java
7c442c1
index 208a373..ce9b4cc 100644
7c442c1
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TabItem.java	
7c442c1
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/TabItem.java	
7c442c1
@@ -293,8 +293,8 @@ public void setControl (Control control) {
7c442c1
 	}
7c442c1
 
7c442c1
 	if (control != null && OS.GTK3) {
7c442c1
-		// See implementation note about bug 454936 at the start of TabFolder.
7c442c1
-		OS.gtk_widget_reparent (control.topHandle (), pageHandle);
7c442c1
+		// To understand why we reparent, see implementation note about bug 454936 at the start of TabFolder.
7c442c1
+		Control.gtk_widget_reparent (control, pageHandle);
7c442c1
 	}
7c442c1
 
7c442c1
 	Control oldControl = this.control, newControl = control;
7c442c1
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
7c442c1
index ccf01ec..c572e51 100644
7c442c1
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java	
7c442c1
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Table.java	
7c442c1
@@ -3649,9 +3649,9 @@ void setParentBackground () {
7c442c1
 }
7c442c1
 
7c442c1
 @Override
7c442c1
-void setParentWindow (Control child) {
7c442c1
-	long /*int*/ window = eventWindow ();
7c442c1
-	OS.gtk_widget_set_parent_window (child.topHandle(), window);
7c442c1
+void setParentGdkWindow (Control child) {
7c442c1
+	long /*int*/ parentGdkWindow = eventWindow ();
7c442c1
+	OS.gtk_widget_set_parent_window (child.topHandle(), parentGdkWindow);
7c442c1
 	/*
7c442c1
 	 * Feature in GTK3: all children of Table have their GdkWindows
7c442c1
 	 * re-parented so they are siblings of the parent Table
7c442c1
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
7c442c1
index 86b72a0..50de17c 100644
7c442c1
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java	
7c442c1
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tree.java	
7c442c1
@@ -3654,9 +3654,9 @@ void setParentBackground () {
7c442c1
 }
7c442c1
 
7c442c1
 @Override
7c442c1
-void setParentWindow (Control child) {
7c442c1
-	long /*int*/ window = eventWindow ();
7c442c1
-	OS.gtk_widget_set_parent_window (child.topHandle(), window);
7c442c1
+void setParentGdkWindow (Control child) {
7c442c1
+	long /*int*/ parentGdkWindow = eventWindow ();
7c442c1
+	OS.gtk_widget_set_parent_window (child.topHandle(), parentGdkWindow);
7c442c1
 	/*
7c442c1
 	 * Feature in GTK3: all children of Tree have their GdkWindows
7c442c1
 	 * re-parented so they are siblings of the parent Tree
7c442c1
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java
7c442c1
index 40fe88c..2da1da5 100644
7c442c1
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java	
7c442c1
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Widget.java	
7c442c1
@@ -936,21 +936,6 @@ long /*int*/ gtk_value_changed (long /*int*/ adjustment) {
7c442c1
 	return 0;
7c442c1
 }
7c442c1
 
7c442c1
-/**
7c442c1
- * Reparent on gtk side.
7c442c1
- * Note: Composites with a setControl() function should probably use this function
7c442c1
- * to correct hierarchy on gtk side.
7c442c1
- * @param widget  the handle to the widget. (usually topHandle())
7c442c1
- * @param newParent  handle to the new widget.
7c442c1
- */
7c442c1
-void gtk_widget_reparent (long /*int*/ widget, long /*int*/ newParent) {
7c442c1
-	//Note, we do not actually call  * 'gtk_widget_reparent(...) as it's deprecated as of gtk 3.14
7c442c1
-	OS.g_object_ref (widget); //so that it won't get destroyed due to lack of references.
7c442c1
-	OS.gtk_container_remove (OS.gtk_widget_get_parent (widget), widget);
7c442c1
-	OS.gtk_container_add (newParent, widget);
7c442c1
-	OS.g_object_unref (widget);
7c442c1
-}
7c442c1
-
7c442c1
 long /*int*/ gtk_window_state_event (long /*int*/ widget, long /*int*/ event) {
7c442c1
 	return 0;
7c442c1
 }