Bug 510446 - [wayland] StyledText DnD not signalling, move drag
detection to mouse_move

Drag detection is moved over to mouse movement instead of on mouse
click.The current way of handling drag detection on mouse click is
broken in Wayland as we cannot hold the mouse click event until a new
event comes up. 

Change-Id: Ib5effea9e44021593bf409481cd8833f2e057be0
Signed-off-by: Ian Pun <ipun@redhat.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java
index 7f412e2..599fbea 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT Custom Widgets/common/org/eclipse/swt/custom/StyledText.java
@@ -171,6 +171,10 @@
 	int blockXAnchor = -1, blockYAnchor = -1;
 	int blockXLocation = -1, blockYLocation = -1;
 
+	/**
+	 * GTK specific DnD variables
+	 */
+	boolean blockSelected, movingSelection, isDragDetecting;
 
 	final static boolean IS_MAC, IS_GTK;
 	static {
@@ -1990,11 +1994,28 @@
 			return dragDetect(event);
 		}
 	} else {
+		if (IS_GTK && isInSelection(event)) {
+			return dragDetect(event);
+		}
 		if (selection.x == selection.y) return false;
 		int offset = getOffsetAtPoint(event.x, event.y, null, true);
 		if (selection.x <= offset && offset < selection.y) {
 			return dragDetect(event);
 		}
+
+	}
+	return false;
+}
+
+private boolean checkDragDetectOnMove(Event event) {
+	if (!isListening(SWT.DragDetect)) return false;
+	if (blockSelection && blockXLocation != -1) {
+		Rectangle rect = getBlockSelectionRectangle();
+		if (rect.contains(event.x, event.y)) {
+			return dragDetect(event);
+		}
+	} else {
+		return dragDetect(event);
 	}
 	return false;
 }
@@ -6076,7 +6097,7 @@
 	forceFocus();
 
 	//drag detect
-	if (dragDetect && checkDragDetect(event)) return;
+	if (!IS_GTK && dragDetect && checkDragDetect(event)) return;
 
 	//paste clipboard selection
 	if (event.button == 2) {
@@ -6099,6 +6120,14 @@
 	}
 	clickCount = event.count;
 	if (clickCount == 1) {
+		if (IS_GTK) {
+			if (isInSelection(event)) {
+				blockSelected = true;
+				return;
+			} else {
+				movingSelection = true;
+			}
+		}
 		boolean select = (event.stateMask & SWT.MOD2) != 0;
 		doMouseLocationChange(event.x, event.y, select);
 	} else {
@@ -6139,7 +6168,26 @@
 	if (clickCount > 0) {
 		update();
 		doAutoScroll(event);
-		doMouseLocationChange(event.x, event.y, true);
+		/* Bug 503431: Handle drag detection within mouse move instead
+		 * of mouse click. We are setting the event.button to 1 because
+		 * mouse movement events do not keep mouse status information
+		 * (whether you move the mouse or you hold a button while moving)
+		 * which is needed for DnD detection.
+		 */
+		if (IS_GTK) {
+			if (dragDetect && isInSelection(event) && !movingSelection) {
+				event.button = 1;
+				event.count = clickCount;
+				checkDragDetectOnMove(event);
+				isDragDetecting = true;
+				return;
+			}
+			if (!isDragDetecting) {
+				doMouseLocationChange(event.x, event.y, true);
+			}
+		} else {
+			doMouseLocationChange(event.x, event.y, true);
+		}
 	}
 	if (renderer.hasLinks) {
 		doMouseLinkCursor(event.x, event.y);
@@ -6150,10 +6198,23 @@
  */
 void handleMouseUp(Event event) {
 	clickCount = 0;
+	movingSelection = false;
 	endAutoScroll();
 	if (event.button == 1) {
 		copySelection(DND.SELECTION_CLIPBOARD);
 	}
+	// set cursor position on release. Related to Bug 503431.
+	if (IS_GTK) {
+		if (blockSelected) {
+			if (!isDragDetecting) {
+				Point caretPosition = defaultCaret.getLocation();
+				doMouseLocationChange(caretPosition.x, caretPosition.y, false);
+			} else {
+				isDragDetecting = false;
+			}
+			blockSelected = false;
+		}
+	}
 }
 /**
  * Renders the invalidated area specified in the paint event.
@@ -7300,6 +7361,20 @@
 boolean isSingleLine() {
 	return (getStyle() & SWT.SINGLE) != 0;
 }
+
+/**
+ * Returns whether the current mouse click is in side a selected area
+ *
+ * @return true if the mouse click event position is inside the
+ * selected area.
+ */
+private boolean isInSelection(Event event) {
+	if (selection.x == selection.y) return false;
+	int offset = getOffsetAtPoint(event.x, event.y, null, true);
+	if (selection.x <= offset && offset < selection.y) return true;
+	return false;
+}
+
 /**
  * Sends the specified verify event, replace/insert text as defined by
  * the event and send a modify event.
diff --git a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/DragSource.java b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/DragSource.java
index 5b31bc4..9286b46 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/DragSource.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT Drag and Drop/gtk/org/eclipse/swt/dnd/DragSource.java
@@ -361,6 +361,14 @@
 	event.doit = operation != 0;
 	event.detail = operation;
 	notifyListeners(DND.DragEnd, event);
+	/*
+	 * send a mouse Up signal for >GTK3.14 as Wayland (support as of 3.14)
+	 * does not trigger a MouseUp/Mouse_release_event on DragEnd.
+	 * See Bug 510446.
+	 */
+	if (OS.GTK_VERSION >= OS.VERSION(3, 14, 0)) {
+		control.notifyListeners(SWT.MouseUp, event);
+	}
 	moveData = false;
 }