Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeo Ufimtsev2018-05-24 14:51:06 -0400
committerAlexander Kurtakov2018-05-28 10:16:20 -0400
commitf387b612b083bd9768b6782dac9356762e8ed1ef (patch)
tree0de3bcc2a6fa68c645dd2e2d7dfd44fed7670b8a
parent8013c7c389dfeba82f5d1fa735b8830665010fab (diff)
downloadeclipse.platform.swt-f387b612b083bd9768b6782dac9356762e8ed1ef.tar.gz
eclipse.platform.swt-f387b612b083bd9768b6782dac9356762e8ed1ef.tar.xz
eclipse.platform.swt-f387b612b083bd9768b6782dac9356762e8ed1ef.zip
Bug 498217 [GTK3][DnD] Dragging parts does not show rectangle (fix)I20180528-2020I20180528-2000
As of Gtk 3.9.1, Commit a60ccd3672467efb454b121993febc36f33cbc79, off-screen GDK windows are not processed. Because of this gtk doesn't send move events to SWT. Platform.UI uses an off-screen tracker for SWT.MOVE events to draw custom rectangles on a transparent shell for it's part-drag-preview. Drawing/updates for these broke because tracker is off screen and no longer sent mouse move events. Solution: If a tracker is to move off-screen, then instead draw it 1x1 and make it transparent. Tests: - Child eclipse. Now part-preview works when dragging editor/views around. - Snippet 31/23 (tracker) work as before. Note, this fix is only for X11. On Wayland part-preview is still broken due to bug 535083. This bugfix seems to make part-preview more fluent on wayland, but there's still a black shell over eclipse. https://bugs.eclipse.org/bugs/show_bug.cgi?id=498217 Change-Id: Ia69c494d3d08b9565e6647073bbfd4870f20ade3 Signed-off-by: Leo Ufimtsev <lufimtse@redhat.com> (cherry picked from commit 34be01e01753fd8ff9109cdad0dad9052e65dd4f)
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tracker.java176
1 files changed, 128 insertions, 48 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tracker.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tracker.java
index 568ec1ad03..21b656031d 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tracker.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Tracker.java
@@ -49,6 +49,12 @@ public class Tracker extends Widget {
Rectangle bounds;
int cursorOrientation = SWT.NONE;
int oldX, oldY;
+ long /*int*/ provider; // Gtk3.14
+
+ // Re-use/cache some items for performance reasons as draw-events must be efficient to prevent jitter.
+ Rectangle cachedCombinedDisplayResolution = Display.getDefault().getBounds(); // Cached for performance reasons.
+ Rectangle cachedUnion = new Rectangle(0, 0, 0, 0);
+ Boolean cachedBackgroundIsOpaque; // Note purposely lazy init.
final static int STEPSIZE_SMALL = 1;
final static int STEPSIZE_LARGE = 9;
@@ -306,6 +312,14 @@ Rectangle [] computeProportions (Rectangle [] rects) {
return result;
}
+/**
+ * Developer note:
+ * - Rectangles can have absolute coords [Tracker(Display)] or relative to parent [Tracker(Composite)]
+ * - This method is called a lot, optimize your code.
+ * - Note, region != rectangle. A region can have a non-squared form, e.g an 'L' shape.
+ *
+ * @param rects
+ */
void drawRectangles (Rectangle [] rects) {
long /*int*/ window = GDK.gdk_get_default_root_window();
if (parent != null) {
@@ -315,48 +329,93 @@ void drawRectangles (Rectangle [] rects) {
if (GTK.GTK3) {
if (overlay == 0) return;
GTK.gtk_widget_shape_combine_region (overlay, 0);
+
+ // Bug 498217.
+ // As of Gtk 3.9.1, Commit a60ccd3672467efb454b121993febc36f33cbc79, off-screen GDK windows are not processed.
+ // Because of this gtk doesn't send move events to SWT. Platform.UI uses an off-screen tracker to draw
+ // custom rectangles for it's part-drag-preview. Drawing/updates for these broke because tracker is off screen.
+ // Solution: If a tracker is to move off-screen, then instead draw it 1x1 and transparent.
+ boolean isOnScreen = true;
+ { // Figure out if the combined rectangles are on or off screen.
+
+ // Produce a single rectangle big enough to contain all rects.
+ // Note, this is different from loop below that creates a Region. (See region != rectangle note in javadoc).
+ cachedUnion.x = rects[0].x;
+ cachedUnion.y = rects[0].y;
+ cachedUnion.width = rects[0].width;
+ cachedUnion.height = rects[0].height;
+ if (rects.length > 1) {
+ for (int i = 1; i < rects.length; i++) {
+ cachedUnion.add(rects[i]);
+ }
+ }
+
+ // Ensure we have absolute screen coordinates. (btw, there are no absolute coordinates on Wayland, so Tracker(Display) is probably broken).
+ if (parent != null) { // if Tracker(Display) has absolute coords. Tracker(Composite) has relative. For relative, we need to find absolute.
+ cachedUnion = display.mapInPixels(parent, null, cachedUnion) ;
+ }
+
+ if (!cachedCombinedDisplayResolution.intersects(cachedUnion)) {
+ isOnScreen = false;
+ }
+ }
+
long /*int*/ region = GDK.gdk_region_new ();
GdkRectangle rect = new GdkRectangle();
- for (int i = 0; i < rects.length; i++) {
- Rectangle r = parent != null ? display.mapInPixels(parent, null, rects[i]) : rects[i];
- rect.x = r.x;
- rect.y = r.y;
- rect.width = r.width + 1;
+ if (isOnScreen) {
+ // Combine Rects into a region. (region is not necessarily a rectangle, E.g it can be 'L' shaped etc..).
+ for (int i = 0; i < rects.length; i++) {
+ // Turn filled rectangles into just the outer lines by drawing one line at a time.
+ Rectangle r = parent != null ? display.mapInPixels(parent, null, rects[i]) : rects[i];
+ rect.x = r.x;
+ rect.y = r.y;
+ rect.width = r.width + 1;
+ rect.height = 1;
+ GDK.gdk_region_union_with_rect(region, rect); // Top line
+ rect.width = 1;
+ rect.height = r.height + 1;
+ GDK.gdk_region_union_with_rect(region, rect); // Left line.
+ rect.x = r.x + r.width;
+ GDK.gdk_region_union_with_rect(region, rect); // Right line.
+ rect.x = r.x;
+ rect.y = r.y + r.height;
+ rect.width = r.width + 1;
+ rect.height = 1;
+ GDK.gdk_region_union_with_rect(region, rect); // Bottom line
+ }
+ setTrackerBackground(true);
+ } else { // Offscreen
+ // part of Bug 498217 fix. Tracker must be at least 1x1 for move events to work.
+ rect.x = 0;
+ rect.y = 0;
rect.height = 1;
- GDK.gdk_region_union_with_rect(region, rect);
rect.width = 1;
- rect.height = r.height + 1;
- GDK.gdk_region_union_with_rect(region, rect);
- rect.x = r.x + r.width;
- GDK.gdk_region_union_with_rect(region, rect);
- rect.x = r.x;
- rect.y = r.y + r.height;
- rect.width = r.width + 1;
- rect.height = 1;
GDK.gdk_region_union_with_rect(region, rect);
+ setTrackerBackground(false);
}
+
GTK.gtk_widget_shape_combine_region (overlay, region);
GDK.gdk_region_destroy (region);
long /*int*/ overlayWindow = GTK.gtk_widget_get_window (overlay);
GDK.gdk_window_hide (overlayWindow);
GDK.gdk_window_show (overlayWindow);
- return;
- }
- long /*int*/ gc = GDK.gdk_gc_new (window);
- if (gc == 0) return;
- long /*int*/ colormap = GDK.gdk_colormap_get_system ();
- GdkColor color = new GdkColor ();
- GDK.gdk_color_white (colormap, color);
- GDK.gdk_gc_set_foreground (gc, color);
- GDK.gdk_gc_set_subwindow (gc, GDK.GDK_INCLUDE_INFERIORS);
- GDK.gdk_gc_set_function (gc, GDK.GDK_XOR);
- for (int i=0; i<rects.length; i++) {
- Rectangle rect = rects [i];
- int x = rect.x;
- if (parent != null && (parent.style & SWT.MIRRORED) != 0) x = parent.getClientWidth () - rect.width - x;
- GDK.gdk_draw_rectangle (window, gc, 0, x, rect.y, rect.width, rect.height);
+ } else { // GTK2
+ long /*int*/ gc = GDK.gdk_gc_new (window);
+ if (gc == 0) return;
+ long /*int*/ colormap = GDK.gdk_colormap_get_system ();
+ GdkColor color = new GdkColor ();
+ GDK.gdk_color_white (colormap, color);
+ GDK.gdk_gc_set_foreground (gc, color);
+ GDK.gdk_gc_set_subwindow (gc, GDK.GDK_INCLUDE_INFERIORS);
+ GDK.gdk_gc_set_function (gc, GDK.GDK_XOR);
+ for (int i=0; i<rects.length; i++) {
+ Rectangle rect = rects [i];
+ int x = rect.x;
+ if (parent != null && (parent.style & SWT.MIRRORED) != 0) x = parent.getClientWidth () - rect.width - x;
+ GDK.gdk_draw_rectangle (window, gc, 0, x, rect.y, rect.width, rect.height);
+ }
+ OS.g_object_unref (gc);
}
- OS.g_object_unref (gc);
}
/**
@@ -759,30 +818,14 @@ public boolean open () {
lastCursor = this.cursor != null ? this.cursor.handle : 0;
if (GTK.GTK3) {
+ cachedCombinedDisplayResolution = Display.getDefault().getBounds(); // In case resolution was changed during run time.
overlay = GTK.gtk_window_new (GTK.GTK_WINDOW_POPUP);
GTK.gtk_window_set_skip_taskbar_hint (overlay, true);
GTK.gtk_window_set_title (overlay, new byte [1]);
GTK.gtk_widget_realize (overlay);
long /*int*/ overlayWindow = GTK.gtk_widget_get_window (overlay);
GDK.gdk_window_set_override_redirect (overlayWindow, true);
- if (GTK.GTK_VERSION < OS.VERSION (3, 14, 0)) {
- GTK.gtk_widget_override_background_color (overlay, GTK.GTK_STATE_FLAG_NORMAL, new GdkRGBA());
- } else {
- String name = GTK.GTK_VERSION >= OS.VERSION(3, 20, 0) ? "window" : "GtkWindow";
- String css = name + " {background-color: rgb(0,0,0);}";
- long /*int*/ provider = 0;
- long /*int*/ context = GTK.gtk_widget_get_style_context (overlay);
- if (provider == 0) {
- provider = GTK.gtk_css_provider_new ();
- GTK.gtk_style_context_add_provider (context, provider, GTK.GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
- OS.g_object_unref (provider);
- }
- GTK.gtk_css_provider_load_from_data (provider, Converter.wcsToMbcs (css, true), -1, null);
- }
- long /*int*/ region = GDK.gdk_region_new ();
- GTK.gtk_widget_shape_combine_region (overlay, region);
- GTK.gtk_widget_input_shape_combine_region (overlay, region);
- GDK.gdk_region_destroy (region);
+ setTrackerBackground(true);
Rectangle bounds = display.getBoundsInPixels();
GTK.gtk_window_move (overlay, bounds.x, bounds.y);
GTK.gtk_window_resize (overlay, bounds.width, bounds.height);
@@ -828,6 +871,43 @@ public boolean open () {
return !cancelled;
}
+private void setTrackerBackground(boolean opaque) {
+ if (cachedBackgroundIsOpaque == null || cachedBackgroundIsOpaque.booleanValue() != opaque) {
+ cachedBackgroundIsOpaque = Boolean.valueOf(opaque);
+ } else if (opaque == cachedBackgroundIsOpaque.booleanValue()) {
+ return;
+ }
+ if (GTK.GTK_VERSION < OS.VERSION (3, 14, 0)) {
+ GTK.gtk_widget_override_background_color (overlay, GTK.GTK_STATE_FLAG_NORMAL, new GdkRGBA());
+ } else {
+ String name = GTK.GTK_VERSION >= OS.VERSION(3, 20, 0) ? "window" : "GtkWindow";
+ String css;
+ if (opaque) {
+ GTK.gtk_widget_set_opacity (overlay, 1.0);
+ css = name + " {background-color: rgb(0,0,0);}";
+ } else {
+ GTK.gtk_widget_set_opacity (overlay, 0.0);
+ css = name + " { "
+ + "border-top-color: transparent;"
+ + "border-left-color: transparent;"
+ + "border-right-color: transparent;"
+ + "border-bottom-color: transparent;}";
+ }
+ long /*int*/ context = GTK.gtk_widget_get_style_context (overlay);
+ if (provider == 0) {
+ provider = GTK.gtk_css_provider_new ();
+ GTK.gtk_style_context_add_provider (context, provider, GTK.GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+ OS.g_object_unref (provider);
+ }
+ GTK.gtk_css_provider_load_from_data (provider, Converter.wcsToMbcs (css, true), -1, null);
+ GTK.gtk_style_context_invalidate (context);
+ }
+ long /*int*/ region = GDK.gdk_region_new ();
+ GTK.gtk_widget_shape_combine_region (overlay, region);
+ GTK.gtk_widget_input_shape_combine_region (overlay, region);
+ GDK.gdk_region_destroy (region);
+}
+
boolean processEvent (long /*int*/ eventPtr) {
GdkEvent gdkEvent = new GdkEvent();
OS.memmove (gdkEvent, eventPtr, GdkEvent.sizeof);

Back to the top