Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c40
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c2
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h2
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java28
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java91
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546274_StyledTextVMCrash.java102
6 files changed, 227 insertions, 38 deletions
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
index 16ae5c75c4..8e32951ff9 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os.c
@@ -2747,6 +2747,26 @@ JNIEXPORT jint JNICALL GDK_NATIVE(_1gdk_1visual_1get_1depth)
}
#endif
+#ifndef NO__1gdk_1window_1begin_1draw_1frame
+JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1window_1begin_1draw_1frame)
+ (JNIEnv *env, jclass that, jlong arg0, jlong arg1)
+{
+ jlong rc = 0;
+ GDK_NATIVE_ENTER(env, that, _1gdk_1window_1begin_1draw_1frame_FUNC);
+/*
+ rc = (jlong)gdk_window_begin_draw_frame((GdkWindow *)arg0, (cairo_region_t *)arg1);
+*/
+ {
+ GDK_LOAD_FUNCTION(fp, gdk_window_begin_draw_frame)
+ if (fp) {
+ rc = (jlong)((jlong (CALLING_CONVENTION*)(GdkWindow *, cairo_region_t *))fp)((GdkWindow *)arg0, (cairo_region_t *)arg1);
+ }
+ }
+ GDK_NATIVE_EXIT(env, that, _1gdk_1window_1begin_1draw_1frame_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1gdk_1window_1create_1similar_1surface
JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1window_1create_1similar_1surface)
(JNIEnv *env, jclass that, jlong arg0, jint arg1, jint arg2, jint arg3)
@@ -2769,6 +2789,26 @@ JNIEXPORT void JNICALL GDK_NATIVE(_1gdk_1window_1destroy)
}
#endif
+#ifndef NO__1gdk_1window_1end_1draw_1frame
+JNIEXPORT jlong JNICALL GDK_NATIVE(_1gdk_1window_1end_1draw_1frame)
+ (JNIEnv *env, jclass that, jlong arg0, jlong arg1)
+{
+ jlong rc = 0;
+ GDK_NATIVE_ENTER(env, that, _1gdk_1window_1end_1draw_1frame_FUNC);
+/*
+ rc = (jlong)gdk_window_end_draw_frame((GdkWindow *)arg0, (GdkDrawingContext *)arg1);
+*/
+ {
+ GDK_LOAD_FUNCTION(fp, gdk_window_end_draw_frame)
+ if (fp) {
+ rc = (jlong)((jlong (CALLING_CONVENTION*)(GdkWindow *, GdkDrawingContext *))fp)((GdkWindow *)arg0, (GdkDrawingContext *)arg1);
+ }
+ }
+ GDK_NATIVE_EXIT(env, that, _1gdk_1window_1end_1draw_1frame_FUNC);
+ return rc;
+}
+#endif
+
#ifndef NO__1gdk_1window_1focus
JNIEXPORT void JNICALL GDK_NATIVE(_1gdk_1window_1focus)
(JNIEnv *env, jclass that, jlong arg0, jint arg1)
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
index 40806b67d5..b0eac77a80 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.c
@@ -212,8 +212,10 @@ char * GDK_nativeFunctionNames[] = {
"_1gdk_1unicode_1to_1keyval",
"_1gdk_1utf8_1to_1string_1target",
"_1gdk_1visual_1get_1depth",
+ "_1gdk_1window_1begin_1draw_1frame",
"_1gdk_1window_1create_1similar_1surface",
"_1gdk_1window_1destroy",
+ "_1gdk_1window_1end_1draw_1frame",
"_1gdk_1window_1focus",
"_1gdk_1window_1get_1children",
"_1gdk_1window_1get_1device_1position",
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
index 935e7d2522..5145d14c27 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/library/os_stats.h
@@ -222,8 +222,10 @@ typedef enum {
_1gdk_1unicode_1to_1keyval_FUNC,
_1gdk_1utf8_1to_1string_1target_FUNC,
_1gdk_1visual_1get_1depth_FUNC,
+ _1gdk_1window_1begin_1draw_1frame_FUNC,
_1gdk_1window_1create_1similar_1surface_FUNC,
_1gdk_1window_1destroy_FUNC,
+ _1gdk_1window_1end_1draw_1frame_FUNC,
_1gdk_1window_1focus_FUNC,
_1gdk_1window_1get_1children_FUNC,
_1gdk_1window_1get_1device_1position_FUNC,
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java
index 62f8fc2ff8..6132c5c132 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/GDK.java
@@ -524,6 +524,34 @@ public class GDK extends OS {
}
/**
* @param window cast=(GdkWindow *)
+ * @param region cast=(cairo_region_t *)
+ * @method flags=dynamic
+ */
+ public static final native long _gdk_window_begin_draw_frame(long window, long region);
+ public static final long gdk_window_begin_draw_frame(long window, long region) {
+ lock.lock();
+ try {
+ return _gdk_window_begin_draw_frame(window, region);
+ } finally {
+ lock.unlock();
+ }
+ }
+ /**
+ * @param window cast=(GdkWindow *)
+ * @param context cast=(GdkDrawingContext *)
+ * @method flags=dynamic
+ */
+ public static final native long _gdk_window_end_draw_frame(long window, long context);
+ public static final long gdk_window_end_draw_frame(long window, long context) {
+ lock.lock();
+ try {
+ return _gdk_window_end_draw_frame(window, context);
+ } finally {
+ lock.unlock();
+ }
+ }
+ /**
+ * @param window cast=(GdkWindow *)
*/
public static final native int _gdk_window_get_state(long window);
/** [GTK3 only, if-def'd in os.h] */
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java
index fc6e3e411b..81e68c30d5 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Canvas.java
@@ -45,7 +45,6 @@ import org.eclipse.swt.internal.gtk.*;
public class Canvas extends Composite {
Caret caret;
IME ime;
- long cachedCairo;
boolean blink, drawFlag;
Canvas () {}
@@ -179,7 +178,6 @@ long gtk_draw (long widget, long cairo) {
result = super.gtk_draw (widget, cairo);
if (isFocus) caret.setFocus ();
} else {
- this.cachedCairo = cairo;
result = super.gtk_draw (widget, cairo);
/*
* blink is needed to be checked as gtk_draw() signals sent from other parts of the canvas
@@ -313,14 +311,19 @@ void reskinChildren (int flags) {
public void scroll (int destX, int destY, int x, int y, int width, int height, boolean all) {
checkWidget();
if (width <= 0 || height <= 0) return;
+ /*
+ * scrollInPixels() doesn't seem to be needed on GTK4, so we can return early.
+ * In fact it doesn't seem to be needed on GTK3 either, but it's been left
+ * here for stability on older GTK3 versions. The investigation
+ * as to why it's unneeded is left as a TODO. See bug 546274.
+ */
+ if (GTK.GTK4) return;
Point destination = DPIUtil.autoScaleUp (new Point (destX, destY));
Rectangle srcRect = DPIUtil.autoScaleUp (new Rectangle (x, y, width, height));
scrollInPixels(destination.x, destination.y, srcRect.x, srcRect.y, srcRect.width, srcRect.height, all);
}
void scrollInPixels (int destX, int destY, int x, int y, int width, int height, boolean all) {
- long cairo = this.cachedCairo;
- if (cairo == 0) return;
if ((style & SWT.MIRRORED) != 0) {
int clientWidth = getClientWidth ();
x = clientWidth - width - x;
@@ -331,12 +334,9 @@ void scrollInPixels (int destX, int destY, int x, int y, int width, int height,
if (!isVisible ()) return;
boolean isFocus = caret != null && caret.isFocusCaret ();
if (isFocus) caret.killFocus ();
- GdkRectangle clipRect = new GdkRectangle ();
- GDK.gdk_cairo_get_clip_rectangle (cairo, clipRect);
+ long window = paintWindow ();
+ long visibleRegion = GDK.gdk_window_get_visible_region (window);
cairo_rectangle_int_t srcRect = new cairo_rectangle_int_t ();
- srcRect.convertFromGdkRectangle(clipRect);
- long gdkResource = GTK.GTK4? paintSurface () : paintWindow ();
- long visibleRegion = Cairo.cairo_region_create_rectangle(srcRect);
srcRect.x = x;
srcRect.y = y;
/*
@@ -384,48 +384,63 @@ void scrollInPixels (int destX, int destY, int x, int y, int width, int height,
redrawWidget (x, y, width, height, false, false, false);
redrawWidget (destX, destY, width, height, false, false, false);
} else {
- Cairo.cairo_push_group(cairo);
- Cairo.cairo_paint(cairo);
- Cairo.cairo_pop_group_to_source(cairo);
+ long cairo = 0;
+ long context = 0;
+ if (GTK.GTK_VERSION >= OS.VERSION(3, 22, 0)) {
+ long cairo_region = GDK.gdk_window_get_visible_region(window);
+ context = GDK.gdk_window_begin_draw_frame(window, cairo_region);
+ cairo = GDK.gdk_drawing_context_get_cairo_context(context);
+ } else {
+ cairo = GDK.gdk_cairo_create(window);
+ }
+ if (Cairo.cairo_version() < Cairo.CAIRO_VERSION_ENCODE(1, 12, 0)) {
+ GDK.gdk_cairo_set_source_window(cairo, window, 0, 0);
+ } else {
+ Cairo.cairo_push_group(cairo);
+ GDK.gdk_cairo_set_source_window(cairo, window, 0, 0);
+ Cairo.cairo_paint(cairo);
+ Cairo.cairo_pop_group_to_source(cairo);
+ }
double[] matrix = {1, 0, 0, 1, -deltaX, -deltaY};
Cairo.cairo_pattern_set_matrix(Cairo.cairo_get_source(cairo), matrix);
Cairo.cairo_rectangle(cairo, copyRect.x + deltaX, copyRect.y + deltaY, copyRect.width, copyRect.height);
Cairo.cairo_clip(cairo);
Cairo.cairo_paint(cairo);
+ if (GTK.GTK_VERSION >= OS.VERSION(3, 22, 0)) {
+ if (context != 0) GDK.gdk_window_end_draw_frame(window, context);
+ } else {
+ Cairo.cairo_destroy(cairo);
+ }
boolean disjoint = (destX + width < x) || (x + width < destX) || (destY + height < y) || (y + height < destY);
if (disjoint) {
- cairo_rectangle_int_t cairoRect = new cairo_rectangle_int_t();
- cairoRect.x = x;
- cairoRect.y = y;
- cairoRect.width = width;
- cairoRect.height = height;
- Cairo.cairo_region_union_rectangle (invalidateRegion, cairoRect);
+ cairo_rectangle_int_t rect = new cairo_rectangle_int_t();
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ Cairo.cairo_region_union_rectangle (invalidateRegion, rect);
} else {
- cairo_rectangle_int_t cairoRect = new cairo_rectangle_int_t();
+ cairo_rectangle_int_t rect = new cairo_rectangle_int_t();
if (deltaX != 0) {
int newX = destX - deltaX;
if (deltaX < 0) newX = destX + width;
- cairoRect.x = newX;
- cairoRect.y = y;
- cairoRect.width = Math.abs(deltaX);
- cairoRect.height = height;
- Cairo.cairo_region_union_rectangle (invalidateRegion, cairoRect);
+ rect.x = newX;
+ rect.y = y;
+ rect.width = Math.abs(deltaX);
+ rect.height = height;
+ Cairo.cairo_region_union_rectangle (invalidateRegion, rect);
}
if (deltaY != 0) {
int newY = destY - deltaY;
if (deltaY < 0) newY = destY + height;
- cairoRect.x = x;
- cairoRect.y = newY;
- cairoRect.width = width;
- cairoRect.height = Math.abs(deltaY);
- Cairo.cairo_region_union_rectangle (invalidateRegion, cairoRect);
+ rect.x = x;
+ rect.y = newY;
+ rect.width = width;
+ rect.height = Math.abs(deltaY);
+ Cairo.cairo_region_union_rectangle (invalidateRegion, rect);
}
}
- if (GTK.GTK4) {
- GDK.gdk_surface_invalidate_region(gdkResource, invalidateRegion);
- } else {
- GDK.gdk_window_invalidate_region(gdkResource, invalidateRegion, all);
- }
+ GDK.gdk_window_invalidate_region(window, invalidateRegion, all);
}
Cairo.cairo_region_destroy (visibleRegion);
Cairo.cairo_region_destroy (copyRegion);
@@ -434,10 +449,10 @@ void scrollInPixels (int destX, int destY, int x, int y, int width, int height,
Control [] children = _getChildren ();
for (int i=0; i<children.length; i++) {
Control child = children [i];
- Rectangle childBounds = child.getBoundsInPixels ();
- if (Math.min(x + width, childBounds.x + childBounds.width) >= Math.max (x, childBounds.x) &&
- Math.min(y + height, childBounds.y + childBounds.height) >= Math.max (y, childBounds.y)) {
- child.setLocationInPixels (childBounds.x + deltaX, childBounds.y + deltaY);
+ Rectangle rect = child.getBoundsInPixels ();
+ if (Math.min(x + width, rect.x + rect.width) >= Math.max (x, rect.x) &&
+ Math.min(y + height, rect.y + rect.height) >= Math.max (y, rect.y)) {
+ child.setLocationInPixels (rect.x + deltaX, rect.y + deltaY);
}
}
}
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546274_StyledTextVMCrash.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546274_StyledTextVMCrash.java
new file mode 100644
index 0000000000..878da10e23
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546274_StyledTextVMCrash.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Syntevo and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Syntevo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.tests.gtk.snippets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+
+public class Bug546274_StyledTextVMCrash {
+ private static class MyStyledText extends StyledText {
+ int cairoCacheSize = 16; // see MAX_FREED_POOL_SIZE in cairo
+ Image tempImages[] = new Image[cairoCacheSize];
+ GC tempGCs[] = new GC[cairoCacheSize];
+
+ public MyStyledText(Composite parent, int style) {
+ super(parent, style);
+ allocTempGCs();
+ }
+
+ void allocTempGCs() {
+ for (int i = 0; i < cairoCacheSize; i++) {
+ tempImages[i] = new Image(this.getDisplay(), 1, 1);
+ tempGCs[i] = new GC(tempImages[i]);
+ }
+ }
+
+ @Override
+ public void scroll(int destX, int destY, int x, int y, int width, int height, boolean all) {
+ // Evaluate with debugger: (cachedCairo.handle == this.cachedCairo);
+ // This already shows that 'this.cachedCairo' can't be used.
+ Image tempImage = new Image(this.getDisplay(), 1, 1);
+ GC cachedCairo = new GC(tempImage);
+
+ // Evict 'cachedCairo' from Cairo's cache 'context_pool' by
+ // 1) Populating cache with free objects
+ // 2) Releasing 'cachedCairo' and it will be truly deleted
+ {
+ if (tempGCs != null) {
+ for (int i = 0; i < tempGCs.length; i++) {
+ tempGCs[i].dispose();
+ tempImages[i].dispose();
+ }
+ }
+
+ cachedCairo.dispose();
+ tempImage.dispose();
+ }
+
+ // Make sure the same malloc() block can't be used again
+ for (int i = 1; i < 1024; i++) {
+ // Intentional leak
+ org.eclipse.swt.internal.gtk.GTK.malloc(i);
+ }
+
+ super.scroll(destX, destY, x, y, width, height, all);
+
+ // Drain Cairo's cache 'context_pool' to force the next cairo to use malloc()
+ allocTempGCs();
+ }
+ }
+
+ public static void main(String[] args) {
+ final Display display = new Display();
+
+ final Shell shell = new Shell(display, SWT.SHELL_TRIM);
+ shell.setLayout(new FillLayout(SWT.VERTICAL));
+ shell.setSize(300, 200);
+
+ String hintText = "Try to horz scroll this StyledText\n" +
+ "\n" +
+ "Horz scrollbar is forced by this long line of text xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+
+ final StyledText text = new MyStyledText(shell, SWT.BORDER | SWT.H_SCROLL);
+ text.setText(hintText);
+
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ display.dispose();
+ }
+}

Back to the top