Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Williams2019-08-13 13:39:32 -0400
committerEric Williams2019-08-16 08:58:18 -0400
commit7081cee06fc084501628dbf6ad48c5e95771a06d (patch)
tree7e7cb8d279489dae3d71a707f3c4fba36d638de8
parentabf0e19e2871518909e2d115840195a894bbce89 (diff)
downloadeclipse.platform.swt-7081cee06fc084501628dbf6ad48c5e95771a06d.tar.gz
eclipse.platform.swt-7081cee06fc084501628dbf6ad48c5e95771a06d.tar.xz
eclipse.platform.swt-7081cee06fc084501628dbf6ad48c5e95771a06d.zip
Bug 546248: [GTK3] Composite receives to much repaint events
As of GTK3.16, GTK will send extra draw events to SwtFixed instances containing overlay scrollbars. This happens when the mouse leaves an SwtFixed instance that has overlay scrollbars attached to it. The fix is to check the dirty region in need of a redraw, and only sent an SWT.Paint event if the actual SwtFixed instance is in need of a redraw. Tested on GTK3.24 on X11 and Wayland. No AllNonBrowser JUnit tests fail. Change-Id: I958b4c16020a14f6f24e6e3d1ca67aba2ebec329 Signed-off-by: Eric Williams <ericwill@redhat.com>
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java13
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Scrollable.java39
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546248_CompositeTooManyPaintEvents.java78
3 files changed, 130 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
index 813c4b0e64..8715917033 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT PI/gtk/org/eclipse/swt/internal/gtk/OS.java
@@ -717,6 +717,11 @@ public class OS extends C {
*/
public static final String GTK_THEME_SET_NAME;
/**
+ * True iff overlay scrolling has been disabled via GTK_OVERLAY_SCROLLING=0.
+ * See bug 546248.
+ */
+ public static final boolean GTK_OVERLAY_SCROLLING_DISABLED;
+ /**
* True if SWT is running on the GNOME desktop environment.
*/
public static final boolean isGNOME;
@@ -769,6 +774,14 @@ public class OS extends C {
GTK_THEME_SET = gtkThemeSet;
GTK_THEME_SET_NAME = gtkThemeName;
+ String scrollingProperty = "GTK_OVERLAY_SCROLLING";
+ String scrollingCheck = getEnvironmentalVariable(scrollingProperty);
+ boolean scrollingDisabled = false;
+ if (scrollingCheck != null && scrollingCheck.equals("0")) {
+ scrollingDisabled = true;
+ }
+ GTK_OVERLAY_SCROLLING_DISABLED = scrollingDisabled;
+
Map<String, String> env = System.getenv();
String desktopEnvironment = env.get("XDG_CURRENT_DESKTOP");
boolean gnomeDetected = false;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Scrollable.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Scrollable.java
index d4a8252ace..2344fbe300 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Scrollable.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Scrollable.java
@@ -304,6 +304,45 @@ public ScrollBar getVerticalBar () {
}
@Override
+long gtk_draw (long widget, long cairo) {
+ /*
+ * Draw events destined for an SwtFixed instance will sometimes
+ * only be redrawing the scrollbars attached to it. GTK will send many
+ * draw events to an SwtFixed instance if:
+ * 1) that instance has overlay scrollbars attached to it, and
+ * 2) the mouse has just left (leave-notify) that SwtFixed widget.
+ *
+ * Such extra draw events cause extra SWT.Paint events to be sent and
+ * reduce performance. The fix is to check if the dirty region in need
+ * of a redraw is the same region that the scroll bars occupy, and ignore
+ * draw events that target such cases. See bug 546248.
+ */
+ boolean overlayScrolling = !OS.GTK_OVERLAY_SCROLLING_DISABLED &&
+ GTK.GTK_VERSION >= OS.VERSION(3, 16, 0);
+ if (overlayScrolling && OS.G_OBJECT_TYPE(widget) == OS.swt_fixed_get_type()) {
+ if ((style & SWT.V_SCROLL) != 0 && verticalBar != null) {
+ GtkAllocation verticalBarAlloc = new GtkAllocation();
+ GTK.gtk_widget_get_allocation(verticalBar.handle, verticalBarAlloc);
+ GdkRectangle rect = new GdkRectangle();
+ GDK.gdk_cairo_get_clip_rectangle(cairo, rect);
+ if (rect.width == verticalBarAlloc.width && rect.height == verticalBarAlloc.height) {
+ return 0;
+ }
+ }
+ if ((style & SWT.H_SCROLL) != 0 && horizontalBar != null) {
+ GtkAllocation horizontalBarAlloc = new GtkAllocation();
+ GTK.gtk_widget_get_allocation(horizontalBar.handle, horizontalBarAlloc);
+ GdkRectangle rect = new GdkRectangle();
+ GDK.gdk_cairo_get_clip_rectangle(cairo, rect);
+ if (rect.width == horizontalBarAlloc.width && rect.height == horizontalBarAlloc.height) {
+ return 0;
+ }
+ }
+ }
+ return super.gtk_draw(widget, cairo);
+}
+
+@Override
long gtk_scroll_event (long widget, long eventPtr) {
long result = super.gtk_scroll_event (widget, eventPtr);
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546248_CompositeTooManyPaintEvents.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546248_CompositeTooManyPaintEvents.java
new file mode 100644
index 0000000000..c4c7f23190
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug546248_CompositeTooManyPaintEvents.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Thomas Singer 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:
+ * Thomas Singer - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.tests.gtk.snippets;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Shell;
+
+public class Bug546248_CompositeTooManyPaintEvents {
+
+ public static void main(String[] args) {
+ final Display display = new Display();
+
+ final StringBuilder buffer = new StringBuilder();
+
+ final int period = 250;
+ display.timerExec(period, new Runnable() {
+ @Override
+ public void run() {
+ if (buffer.length() > 0) {
+ System.out.println(DateFormat.getTimeInstance().format(new Date()) + ": " + buffer);
+ buffer.setLength(0);
+ }
+ if (!display.isDisposed()) {
+ display.timerExec(period, this);
+ }
+ }
+ });
+
+ final Shell shell = new Shell(display);
+ shell.setLayout(new FillLayout());
+
+ final Composite composite = new Composite(shell, SWT.DOUBLE_BUFFERED | SWT.V_SCROLL);
+ final Listener listener = event -> {
+ if (event.type == SWT.Paint) {
+ buffer.append('p');
+ event.gc.drawText("Hello world", 0, 0);
+ }
+ else if (event.type == SWT.MouseMove) {
+ buffer.append('m');
+ }
+ else if (event.type == SWT.MouseHover) {
+ buffer.append('h');
+ }
+ };
+ composite.addListener(SWT.Paint, listener);
+ composite.addListener(SWT.MouseMove, listener);
+ composite.addListener(SWT.MouseHover, listener);
+
+ shell.setSize(400, 300);
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ display.dispose();
+ }
+}

Back to the top