Bug 441602: Shell#setRegion fails to mirror for RTL context
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 7a8a070..21bcff6 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
@@ -12,10 +12,11 @@
 
 
 import org.eclipse.swt.*;
-import org.eclipse.swt.internal.*;
-import org.eclipse.swt.internal.gtk.*;
+import org.eclipse.swt.events.ShellListener;
 import org.eclipse.swt.graphics.*;
-import org.eclipse.swt.events.*;
+import org.eclipse.swt.internal.Converter;
+import org.eclipse.swt.internal.cairo.Cairo;
+import org.eclipse.swt.internal.gtk.*;
 
 /**
  * Instances of this class represent the "windows"
@@ -125,6 +126,7 @@
 	Control lastActive;
 	ToolTip [] toolTips;
 	boolean ignoreFocusOut;
+	Region originalRegion;
 
 	static final int MAXIMUM_TRIM = 128;
 	static final int BORDER = 3;
@@ -1142,6 +1144,7 @@
 public Region getRegion () {
 	/* This method is needed for @since 3.0 Javadoc */
 	checkWidget ();
+	if (originalRegion != null) return originalRegion;
 	return region;
 }
 
@@ -2115,7 +2118,55 @@
 public void setRegion (Region region) {
 	checkWidget ();
 	if ((style & SWT.NO_TRIM) == 0) return;
+	
+	Region regionToDispose = null;
+	if ((style & SWT.RIGHT_TO_LEFT) != 0) {
+		if (originalRegion != null) regionToDispose = this.region;
+		originalRegion = region;
+		region = mirrorRegion (region);
+	} else {
+		originalRegion = null;
+	}
+	if (region != null) {
+		Rectangle bounds = region.getBounds();
+		setSize(bounds.x + bounds.width, bounds.y + bounds.height);
+	}
 	super.setRegion (region);
+	if (regionToDispose != null) regionToDispose.dispose();
+}
+
+//copied from Region:
+static void gdk_region_get_rectangles(long /*int*/ region, long /*int*/[] rectangles, int[] n_rectangles) {
+	if (!OS.GTK3) {
+		OS.gdk_region_get_rectangles (region, rectangles, n_rectangles);
+		return;
+	}
+	int num = Cairo.cairo_region_num_rectangles (region);
+	if (n_rectangles != null) n_rectangles[0] = num;
+	rectangles[0] = OS.g_malloc(GdkRectangle.sizeof * num);
+	for (int n = 0; n < num; n++) {
+		Cairo.cairo_region_get_rectangle (region, n, rectangles[0] + (n * GdkRectangle.sizeof));
+	}
+}
+
+static Region mirrorRegion(Region region) {
+	if (region == null) return null;
+	
+	Region mirrored = new Region(region.getDevice());
+
+	long /*int*/ rgn = region.handle;
+	int[] nRects = new int[1];
+	long /*int*/[] rects = new long /*int*/[1];
+	gdk_region_get_rectangles(rgn, rects, nRects);
+	Rectangle bounds = region.getBounds();
+	GdkRectangle rect = new GdkRectangle();
+	for (int i=0; i<nRects[0]; i++) {
+		OS.memmove(rect, rects[0] + (i * GdkRectangle.sizeof), GdkRectangle.sizeof);
+		rect.x = bounds.x + bounds.width - rect.x - rect.width;
+		OS.gdk_region_union_with_rect(mirrored.handle, rect);
+	}
+	if (rects[0] != 0) OS.g_free(rects[0]);
+	return mirrored;
 }
 
 /*
@@ -2548,6 +2599,8 @@
 
 @Override
 void releaseWidget () {
+	Region regionToDispose = null;
+	if (originalRegion != null) regionToDispose  = region;
 	super.releaseWidget ();
 	destroyAccelGroup ();
 	display.clearModal (this);
@@ -2561,6 +2614,9 @@
 		OS.gdk_window_remove_filter(window, display.filterProc, shellHandle);
 	}
 	lastActive = null;
+	if (regionToDispose != null) {
+		regionToDispose.dispose();
+	}
 }
 
 void setToolTipText (long /*int*/ tipWidget, String string) {
@@ -2706,11 +2762,11 @@
 	if (!mapped) {
 		/*
 		 * Special case: The handle attributes are not initialized until the
-		 * shell is made visible, so gdk_window_get_origin () will return {0, 0}.
+		 * shell is made visible, so gdk_window_get_origin () always returns {0, 0}.
 		 * 
 		 * Once the shell is realized, gtk_window_get_position () includes
 		 * window trims etc. from the window manager. That's why getLocation ()
-		 * is not safe to use after the shell has been made visible.
+		 * is not safe to use for coordinate mappings after the shell has been made visible.
 		 */
 		return getLocation ();
 	}