Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Williams2019-07-12 16:53:03 +0000
committerEric Williams2019-07-22 13:07:40 +0000
commit3f4ba4829811a53d8db59b35fed6a7d8a078aca9 (patch)
tree9d9f95b263c0a5020f10194c4c1af16df95d4df0
parent5d3248a3c64029366485c6f45cf72e8a4e8cc51e (diff)
downloadeclipse.platform.swt-3f4ba4829811a53d8db59b35fed6a7d8a078aca9.tar.gz
eclipse.platform.swt-3f4ba4829811a53d8db59b35fed6a7d8a078aca9.tar.xz
eclipse.platform.swt-3f4ba4829811a53d8db59b35fed6a7d8a078aca9.zip
Bug 507020: [WAYLAND] [HiDPI] Some icons scaled incorrect
Using gdk_get_default_root_window() isn't reliable enough to give us an accurate scale factor. Instead, we can check the scale factor of the Cairo surface provided in gtk_draw(). This information will let us know whether GTK has already scaled the Widget/Cairo surface, meaning SWT doesn't have to manually scale it again. This change only applies to GNOME. Tested on X11 and Wayland on GTK3.24. In both instances, no more double scaling is observed. Change-Id: I9271576e66af857962384264eb5645235aa88feb 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.java15
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Device.java2
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java34
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java3
-rw-r--r--tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug507020_WaylandIconsDoubleScaled.java63
5 files changed, 114 insertions, 3 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 166b509743..b6a3080f7f 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
@@ -15,6 +15,8 @@
package org.eclipse.swt.internal.gtk;
+import java.util.*;
+
import org.eclipse.swt.internal.*;
// Common type translation table:
@@ -720,6 +722,11 @@ public class OS extends C {
*/
public static final boolean GTK_THEME_DARK;
+ /**
+ * True if SWT is running on the GNOME desktop environment.
+ */
+ public static final boolean isGNOME;
+
/* Feature in Gtk: with the switch to GtkMenuItems from GtkImageMenuItems
* in Gtk3 came a small Gtk shortfall: a small amount of padding on the left hand
* side of MenuItems was added. This padding is not accessible to the developer,
@@ -772,6 +779,14 @@ public class OS extends C {
GTK_THEME_NAME = gtkThemeName;
GTK_THEME_DARK = gtkThemeDark;
+ Map<String, String> env = System.getenv();
+ String desktopEnvironment = env.get("XDG_CURRENT_DESKTOP");
+ boolean gnomeDetected = false;
+ if (desktopEnvironment != null) {
+ gnomeDetected = desktopEnvironment.contains("GNOME");
+ }
+ isGNOME = gnomeDetected;
+
System.setProperty("org.eclipse.swt.internal.gtk.version",
(GTK.GTK_VERSION >>> 16) + "." + (GTK.GTK_VERSION >>> 8 & 0xFF) + "." + (GTK.GTK_VERSION & 0xFF));
// set GDK backend if we are on X11
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Device.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Device.java
index 73c02b1702..b96dc1a0ad 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Device.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/graphics/Device.java
@@ -670,7 +670,7 @@ protected void init () {
surface = GDK.gdk_window_create_similar_surface(gdkResource, Cairo.CAIRO_CONTENT_COLOR, 10, 10);
}
Cairo.cairo_surface_get_device_scale(surface, sx, sy);
- DPIUtil.setUseCairoAutoScale((sx[0]*100) == scaleFactor);
+ DPIUtil.setUseCairoAutoScale((sx[0]*100) == scaleFactor || OS.isGNOME);
}
/* Initialize the system font slot */
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
index 9fcdc2a649..7bdbd8f6fc 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Control.java
@@ -120,6 +120,21 @@ public abstract class Control extends Widget implements Drawable {
static boolean mouseDown;
boolean dragBegun;
+ /**
+ * Flag to check the scale factor upon the first drawing of this Control.
+ * This is done by checking the scale factor of the Cairo surface in gtk_draw().
+ *
+ * Doing so provides an accurate scale factor, and will determine if this Control
+ * needs to be scaled manually by SWT. See bug 507020.
+ */
+ boolean checkScaleFactor = true;
+
+ /**
+ * True if GTK has autoscaled this Control, meaning SWT does not need to do any
+ * manual scaling. See bug 507020.
+ */
+ boolean autoScale = true;
+
Control () {
}
@@ -1549,6 +1564,12 @@ boolean isActive () {
return getShell ().getModalShell () == null && display.getModalDialog () == null;
}
+@Override
+public boolean isAutoScalable () {
+ return autoScale;
+}
+
+
/*
* Answers a boolean indicating whether a Label that precedes the receiver in
* a layout should be read by screen readers as the recevier's label.
@@ -3872,6 +3893,19 @@ void cairoClipRegion (long cairo) {
@Override
long gtk_draw (long widget, long cairo) {
+ if (checkScaleFactor) {
+ long surface = Cairo.cairo_get_target(cairo);
+ if (surface != 0) {
+ double [] sx = new double [1];
+ double [] sy = new double [1];
+ Cairo.cairo_surface_get_device_scale(surface, sx, sy);
+ long display = GDK.gdk_display_get_default();
+ long monitor = GDK.gdk_display_get_monitor_at_point(display, 0, 0);
+ int scale = GDK.gdk_monitor_get_scale_factor(monitor);
+ autoScale = !(scale == Math.round(sx[0]));
+ checkScaleFactor = false;
+ }
+ }
if ((state & OBSCURED) != 0) return 0;
GdkRectangle rect = new GdkRectangle ();
GDK.gdk_cairo_get_clip_rectangle (cairo, rect);
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
index 92248562e9..013074eb13 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java
@@ -1063,8 +1063,7 @@ void checkIMModule () {
System.err.println("***WARNING: Unset GTK_IM_MODULE or set GTK_IM_MODULE=ibus if flicking is experienced. ");
}
// Enforce ibus as the input module on GNOME
- String desktopEnvironment = env.get("XDG_CURRENT_DESKTOP");
- if ("GNOME".equals(desktopEnvironment)) {
+ if (OS.isGNOME) {
long settings = GTK.gtk_settings_get_default ();
byte[] ibus = Converter.wcsToMbcs ("ibus", true);
if (settings != 0) OS.g_object_set (settings, GTK.gtk_im_module, ibus, 0);
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug507020_WaylandIconsDoubleScaled.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug507020_WaylandIconsDoubleScaled.java
new file mode 100644
index 0000000000..49bb534ffa
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug507020_WaylandIconsDoubleScaled.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2019 Red Hat 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:
+ * Red Hat - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.tests.gtk.snippets;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+
+public class Bug507020_WaylandIconsDoubleScaled {
+
+ public static void main (String [] args) {
+ final Display display = new Display ();
+ final Shell shell = new Shell (display);
+ shell.setText("Bug507020: Wayland Double Scaling");
+ shell.setLayout (new GridLayout (1, false));
+
+ new Label (shell, SWT.NONE).setText ("1. Canvas\n(PaintListener)");
+ final Point size = new Point (100, 40);
+ final Canvas canvas = new Canvas (shell, SWT.NONE);
+ canvas.addPaintListener (e -> {
+ Point size1 = canvas.getSize ();
+ paintGradient (e.gc, size1);
+ });
+ GridData gridData = new GridData (size.x, size.y);
+ gridData.horizontalSpan = 2;
+ canvas.setLayoutData (gridData);
+
+ new Label (shell, SWT.NONE).setText ("5. 50x50 box\n(Display#getDPI(): " + display.getDPI().x + ")");
+ Label box= new Label (shell, SWT.NONE);
+ box.setBackground(display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));
+ box.setLayoutData (new GridData (50, 50));
+
+ shell.pack ();
+ shell.open ();
+ while (!shell.isDisposed ()) {
+ if (!display.readAndDispatch ()) display.sleep ();
+ }
+ display.dispose ();
+ }
+
+ private static void paintGradient (GC gc, Point size) {
+ // Minimal gradient example
+ gc.setBackground (gc.getDevice ().getSystemColor (SWT.COLOR_LIST_SELECTION));
+ gc.fillGradientRectangle(0, 0, size.x, size.y, true);
+ }
+}

Back to the top