135946 - Virtual Tree eats shell activations
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
index ecca358..fd88aa1 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
@@ -1364,11 +1364,8 @@
 					break;
 			}
 		}
-		return 0;
-	} 
-	Widget widget = getWidget (data);
-	if (widget == null) return 0;
-	return widget.filterProc (xEvent, gdkEvent, data);
+	}
+	return 0;
 }
 
 /**
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java
index 4c159ab..5762183 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java
@@ -432,7 +432,21 @@
 			if (focusHandle != 0 && !OS.GTK_WIDGET_HAS_FOCUS (focusHandle)) return;
 		}
 	}
+	/*
+	* Bug in GTK.  When a shell that is not managed by the window
+	* manage is given focus, GTK gets stuck in "focus follows pointer"
+	* mode when the pointer is within the shell and its parent when
+	* the shell is hidden or disposed. The fix is to use XSetInputFocus()
+	* to assign focus when ever the active shell has not managed by
+	* the window manager.
+	* 
+	* NOTE: This bug is fixed in GTK+ 2.6.8 and above.
+	*/
+	boolean xFocus = false;
 	if (activeShell != null) {
+		if (OS.GTK_VERSION < OS.VERSION (2, 6, 8)) {
+			xFocus = (activeShell.style & SWT.ON_TOP) != 0;
+		}
 		display.activeShell = null;
 		display.activePending = true;
 	}
@@ -443,7 +457,7 @@
 	* the focus.
 	*/
 	int /*long*/ window = OS.GTK_WIDGET_WINDOW (shellHandle);
-	if ((style & SWT.ON_TOP) != 0 && OS.GDK_WINDOWING_X11 ()) {
+	if ((xFocus || (style & SWT.ON_TOP) != 0) && OS.GDK_WINDOWING_X11 ()) {
 		int /*long*/ xDisplay = OS.gdk_x11_drawable_get_xdisplay (window);
 		int /*long*/ xWindow = OS.gdk_x11_drawable_get_xid (window);
 		OS.gdk_error_trap_push ();
@@ -630,35 +644,21 @@
 	return shellHandle;
 }
 
-int /*long*/ filterProc (int /*long*/ xEvent, int /*long*/ gdkEvent, int /*long*/ data) {
-	/*
-	* Bug in GTK.  When a shell that has no window manager trimmings
-	* is given focus, GTK gets stuck in "focus follows pointer" mode when
-	* the pointer is within the shell and its parent when the shell is disposed.
-	* The fix is to modify the X events that cause this to happen.
-	*/
-	XFocusChangeEvent focusEvent = new XFocusChangeEvent ();
-	OS.memmove (focusEvent, xEvent, 4);
-	switch (focusEvent.type) {
-		case OS.FocusIn: {
-			OS.memmove (focusEvent, xEvent, XFocusChangeEvent.sizeof);
-			if (focusEvent.detail == OS.NotifyPointer) {
-				focusEvent.detail = OS.NotifyNonlinear;
-				OS.memmove (xEvent, focusEvent, XFocusChangeEvent.sizeof);
+void fixActiveShell () {
+	if (display.activeShell == this) {
+		Shell shell = null;
+		if (parent != null && parent.isVisible ()) shell = parent.getShell ();
+		if (shell == null && (style & SWT.ON_TOP) != 0) {
+			Shell [] shells = display.getShells ();
+			for (int i = 0; i < shells.length; i++) {
+				if (shells [i] != null && shells [i].isVisible ()) {
+					shell = shells [i];
+					break;
+				}
 			}
-			break;
 		}
-		case OS.EnterNotify: {
-			XCrossingEvent crossingEvent = new XCrossingEvent ();
-			OS.memmove (crossingEvent, xEvent, XCrossingEvent.sizeof);
-			if (crossingEvent.focus) {
-				crossingEvent.focus = false;
-				OS.memmove (xEvent, crossingEvent, XCrossingEvent.sizeof);
-			}
-			break;
-		}
+		if (shell != null) shell.bringToTop (false);
 	}
-	return 0;
 }
 
 void fixShell (Shell newShell, Control control) {
@@ -933,17 +933,6 @@
 	if ((style & SWT.ON_TOP) != 0) {
 		OS.gdk_window_set_override_redirect (window, true);
 	}
-	/*
-	* Bug in GTK.  When a shell that has no window manager trimmings
-	* is given focus, GTK gets stuck in "focus follows pointer" mode when
-	* the pointer is within the shell and its parent when the shell is disposed.
-	* The fix is to modify the X events that cause this to happen.
-	* 
-	* NOTE: This bug is fixed in GTK+ 2.6.8 and above.
-	*/
-	if (OS.GTK_VERSION < OS.VERSION (2, 6, 8)) {
-		OS.gdk_window_add_filter  (window, display.filterProc, shellHandle);
-	}
 	return result;
 }
 
@@ -1470,7 +1459,8 @@
 				updateLayout (false);
 			}
 		}
-	} else {	
+	} else {
+		fixActiveShell ();
 		OS.gtk_widget_hide (shellHandle);
 		sendEvent (SWT.Hide);
 	}
@@ -1557,21 +1547,8 @@
 	* more than once.  If this happens, fail silently.
 	*/
 	if (isDisposed()) return;
-
-	/*
-	* Feature in GTK.  When the active shell is disposed,
-	* GTK assigns focus temporarily to the root window
-	* unless it has previously been told to do otherwise.
-	* The fix is to make the parent be the active top level
-	* shell when the child shell is disposed.
-	*/
+	fixActiveShell ();
 	OS.gtk_widget_hide (shellHandle);
-	if (parent != null) {
-		if (display.activeShell == this) {
-			Shell shell = parent.getShell ();	
-			shell.bringToTop (false);
-		}
-	}
 	super.dispose ();
 }
 
@@ -1632,10 +1609,6 @@
 	if (display.activeShell == this) display.activeShell = null;
 	if (tooltipsHandle != 0) OS.g_object_unref (tooltipsHandle);
 	tooltipsHandle = 0;
-	if (OS.GTK_VERSION < OS.VERSION (2, 6, 8) ) {
-		int /*long*/ window = OS.GTK_WIDGET_WINDOW (shellHandle);
-		OS.gdk_window_remove_filter  (window, display.filterProc, shellHandle);
-	}
 	region = null;
 	lastActive = null;
 }
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
index a6db1b4..dd4382c 100644
--- 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
@@ -792,10 +792,6 @@
 	return display.filters (eventType);
 }
 
-int /*long*/ filterProc (int /*long*/ xEvent, int /*long*/ gdkEvent, int /*long*/ data) {
-	return 0;
-}
-
 int /*long*/ fixedMapProc (int /*long*/ widget) {
 	return 0;
 }