diff options
author | Eric Williams | 2019-07-12 16:53:03 +0000 |
---|---|---|
committer | Eric Williams | 2019-07-22 13:07:40 +0000 |
commit | 3f4ba4829811a53d8db59b35fed6a7d8a078aca9 (patch) | |
tree | 9d9f95b263c0a5020f10194c4c1af16df95d4df0 | |
parent | 5d3248a3c64029366485c6f45cf72e8a4e8cc51e (diff) | |
download | eclipse.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>
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); + } +} |