Added more logic to getting the screen DPI + scaling.

This commit is contained in:
nathan 2017-07-09 01:35:52 +02:00
parent 22a61f29ca
commit ee1be59dc3

View File

@ -5,8 +5,11 @@ import static dorkbox.systemTray.util.CssParser.removeComments;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@ -21,11 +24,11 @@ import dorkbox.systemTray.util.CssParser;
import dorkbox.systemTray.util.CssParser.Css;
import dorkbox.systemTray.util.CssParser.CssNode;
import dorkbox.systemTray.util.CssParser.Entry;
import dorkbox.systemTray.util.SizeAndScalingUtil;
import dorkbox.util.FileUtil;
import dorkbox.util.MathUtil;
import dorkbox.util.OS;
import dorkbox.util.OSUtil;
import dorkbox.util.process.ShellProcessBuilder;
/**
* Class to contain all of the methods needed to get the text color from the AppIndicator/GtkStatusIcon menu entry. This is primarily
@ -150,75 +153,249 @@ class GtkTheme {
*/
public static
int getIndicatorSize(final Class<? extends Tray> trayType) {
// double scalingFactor = getLinuxScalingFactor();
//
// if (scalingFactor > 1) {
// return scalingFactor;
// }
//
// // fedora 23+ has a different size for the indicator (NOT default 16px)
// int fedoraVersion = OSUtil.Linux.getFedoraVersion();
//
// if (fedoraVersion >= 23) {
// System.err.println("FEDORA SCALE? ");
//// if (SystemTray.DEBUG) {
//// SystemTray.logger.debug("Adjusting tray/menu scaling for FEDORA " + fedoraVersion);
//// }
//
// return 2;
//// trayScalingFactor = 2;
// }
//
// return 0;
// Linux is similar enough, that it just uses this method
// https://wiki.archlinux.org/index.php/HiDPI
// 96 DPI is the default
final double defaultDPI = 96.0;
final AtomicReference<Double> screenScale = new AtomicReference<Double>();
final AtomicInteger screenDPI = new AtomicInteger();
Gtk.dispatchAndWait(new Runnable() {
@Override
public
void run() {
// screen DPI
Pointer screen = Gtk.gdk_screen_get_default();
if (screen != null) {
// this call makes NO SENSE, but reading the documentation shows it is the CORRECT call.
screenDPI.set((int) Gtk.gdk_screen_get_resolution(screen));
}
if (Gtk.isGtk3) {
Pointer window = Gtk.gdk_get_default_root_window();
if (window != null) {
screenScale.set((double) Gtk3.gdk_window_get_scale_factor(window));
}
}
}
});
// fallback
if (screenDPI.get() == 0) {
// GET THE DPI IN LINUX
// https://wiki.archlinux.org/index.php/Talk:GNOME
Object detectedValue = Toolkit.getDefaultToolkit().getDesktopProperty("gnome.Xft/DPI");
if (detectedValue instanceof Integer) {
int dpi = ((Integer) detectedValue) / 1024;
if (dpi == -1) {
screenDPI.set((int) defaultDPI);
}
if (dpi < 50) {
// 50 dpi is the minimum value gnome allows
screenDPI.set(50);
}
}
}
// check system ENV variables.
if (screenScale.get() == 0) {
String envVar = System.getenv("QT_AUTO_SCREEN_SCALE_FACTOR");
if (envVar != null) {
try {
screenScale.set(Double.parseDouble(envVar));
} catch (Exception ignored) {
}
}
}
// check system ENV variables.
if (screenScale.get() == 0) {
String envVar = System.getenv("QT_SCALE_FACTOR");
if (envVar != null) {
try {
screenScale.set(Double.parseDouble(envVar));
} catch (Exception ignored) {
}
}
}
// check system ENV variables.
if (screenScale.get() == 0) {
String envVar = System.getenv("GDK_SCALE");
if (envVar != null) {
try {
screenScale.set(Double.parseDouble(envVar));
} catch (Exception ignored) {
}
}
}
// check system ENV variables.
if (screenScale.get() == 0) {
String envVar = System.getenv("ELM_SCALE");
if (envVar != null) {
try {
screenScale.set(Double.parseDouble(envVar));
} catch (Exception ignored) {
}
}
}
OSUtil.DesktopEnv.Env env = OSUtil.DesktopEnv.get();
// sometimes the scaling-factor is set
if (env == OSUtil.DesktopEnv.Env.Gnome) {
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(8196);
PrintStream outputStream = new PrintStream(byteArrayOutputStream);
// gsettings get org.gnome.desktop.interface scaling-factor
final ShellProcessBuilder shellVersion = new ShellProcessBuilder(outputStream);
shellVersion.setExecutable("gsettings");
shellVersion.addArgument("get");
shellVersion.addArgument("org.gnome.desktop.interface");
shellVersion.addArgument("scaling-factor");
shellVersion.start();
String output = ShellProcessBuilder.getOutput(byteArrayOutputStream);
if (!output.isEmpty()) {
// DEFAULT icon size is 16. HiDpi changes this scale, so we should use it as well.
// should be: uint32 0 or something
if (output.contains("uint32")) {
String value = output.substring(output.indexOf("uint") + 7, output.length());
// 0 is disabled (no scaling)
// 1 is enabled (default scale)
// 2 is 2x scale
// 3 is 3x scale
// etc
double scalingFactor = Double.parseDouble(value);
if (scalingFactor >= 1) {
screenScale.set(scalingFactor);
}
// A setting of 2, 3, etc, which is all you can do with scaling-factor
// To enable HiDPI, use gsettings:
// gsettings set org.gnome.desktop.interface scaling-factor 2
}
}
} catch (Throwable ignore) {
}
}
else if (OSUtil.DesktopEnv.isKDE()) {
// check the custom KDE override file
try {
File customSettings = new File("/usr/bin/startkde-custom");
if (customSettings.canRead()) {
List<String> lines = FileUtil.readLines(customSettings);
for (String line : lines) {
String str = "export GDK_SCALE=";
int i = line.indexOf(str);
if (i > -1) {
String scale = line.substring(i + str.length());
double scalingFactor = Double.parseDouble(scale);
if (scalingFactor >= 1) {
screenScale.set(scalingFactor);
break;
}
}
}
}
} catch (Exception ignored) {
}
}
// System.err.println("screen scale: " + screenScale.get());
// System.err.println("screen DPI: " + screenDPI.get());
if (OSUtil.DesktopEnv.isKDE()) {
// KDE
/*
* Tray icons with fixed size
* If the tray icons are not scaled with the rest of the desktop, the size can be set editing the default value for iconSize
* in /usr/share/plasma/plasmoids/org.kde.plasma.private.systemtray/contents/config/main.xml
* (e.g. the value 2 may be fine):
*
* /usr/share/plasma/plasmoids/org.kde.plasma.private.systemtray/contents/config/main.xml
* <entry name="iconSize" type="Int">
* <label>Default icon size for the systray icons, it's an enum which values mean,
* Small, SmallMedium, Medium, Large, Huge, Enormous respectively. On low DPI systems they correspond to
* 16, 22, 32, 48, 64, 128 pixels. On high DPI systems those values would be scaled up, depending on the DPI.
* </label>
* <default>2</default>
* </entry>
* Looking in plasma-framework/src/declarativeimports/core/units.cpp:
// Scale the icon sizes up using the devicePixelRatio
// This function returns the next stepping icon size
// and multiplies the global settings with the dpi ratio.
const qreal ratio = devicePixelRatio();
if (ratio < 1.5) {
return size;
} else if (ratio < 2.0) {
return size * 1.5;
} else if (ratio < 2.5) {
return size * 2.0;
} else if (ratio < 3.0) {
return size * 2.5;
} else if (ratio < 3.5) {
return size * 3.0;
} else {
return size * ratio;
}
My ratio is 1.47674, that means I have no scaling at all when there is a 1.5 factor existing. Is it reasonable? Wouldn't it make more sense to use the factor the closest to the ratio rather than what is done here?
*/
File mainFile = new File("/usr/share/plasma/plasmoids/org.kde.plasma.private.systemtray/contents/config/main.xml");
if (mainFile.canRead()) {
List<String> lines = FileUtil.readLines(mainFile);
boolean found = false;
int index = 0;
for (final String line : lines) {
if (line.contains("<entry name=\"iconSize\" type=\"Int\">")) {
found = true;
// have to get the "default" line value
}
String str = "<default>";
if (found && (index = line.indexOf(str)) > -1) {
// this is our line. now get the value.
String substring = line.substring(index + str.length(), line.indexOf("</default>", index));
if (MathUtil.isInteger(substring)) {
// Default icon size for the systray icons, it's an enum which values mean,
// Small, SmallMedium, Medium, Large, Huge, Enormous respectively.
// On low DPI systems they correspond to :
// 16, 22, 32, 48, 64, 128 pixels.
// On high DPI systems those values would be scaled up, depending on the DPI.
int imageSize = 0;
int imageSizeEnum = Integer.parseInt(substring);
switch (imageSizeEnum) {
case 0:
imageSize = 16;
break;
case 1:
imageSize = 22;
break;
case 2:
imageSize = 32;
break;
case 3:
imageSize = 48;
break;
case 4:
imageSize = 64;
break;
case 5:
imageSize = 128;
break;
}
if (imageSize > 0) {
double scaleRatio = screenDPI.get() / defaultDPI;
return (int) (scaleRatio * imageSize);
}
}
}
}
}
}
else {
double linuxScalingFactor = SizeAndScalingUtil.getLinuxScalingFactor();
// final AtomicInteger screenScale = new AtomicInteger();
// final AtomicReference<Double> screenDPI = new AtomicReference<Double>();
//
// Gtk.dispatchAndWait(new Runnable() {
// @Override
// public
// void run() {
// // screen DPI
// Pointer screen = Gtk.gdk_screen_get_default();
// if (screen != null) {
// // this call makes NO SENSE, but reading the documentation shows it is the CORRECT call.
// screenDPI.set(Gtk.gdk_screen_get_resolution(screen));
// }
//
// if (Gtk.isGtk3) {
// Pointer window = Gtk.gdk_get_default_root_window();
// if (window != null) {
// screenScale.set(Gtk3.gdk_window_get_scale_factor(window));
// }
// }
// }
// });
// TODO: what to do with screen DPI? 72 is default? 96 is default (yes, i think)?
OSUtil.DesktopEnv.Env env = OSUtil.DesktopEnv.get();
if (OSUtil.Linux.isUbuntu() && env == OSUtil.DesktopEnv.Env.Unity) {
// if we measure on ubuntu unity using a screen shot (using swing, so....) , the max size was 24, HOWEVER this goes from
// the top->bottom of the indicator bar -- and since it was swing, it uses a different rendering method and it (honestly)
@ -299,78 +476,12 @@ class GtkTheme {
});
int i = traySize.get();
System.err.println("TRAY SIZE: " + traySize.get());
// System.err.println("SCREEN DPI: " + screenDPI.get());
// System.err.println("SCREEN SCALE: " + screenScale.get());
if (i != 0) {
return i;
}
}
}
// void
// gtk_widget_get_preferred_height (GtkWidget *widget,
// gint *minimum_height,
// gint *natural_height);
// g_param_spec_int ("check-icon-size",
// "Check icon size",
// "Check icon size",
// -1, G_MAXINT, 40,
// G_PARAM_READWRITE));
// -GtkCheckButton-indicator-size: 15;
// -GtkCheckMenuItem-indicator-size: 14;
// https://wiki.gnome.org/HowDoI/HiDpi
// String css = getCss();
// -GtkCheckButton-indicator-size: 16;
// -GtkCheckMenuItem-indicator-size: 16;
// xdpyinfo | grep dots reported 96x96 dots
// else it's an app indicator
// if we can get the theme path, the theme path will (almost always) have size info as part of the path name!
// app_indicator_get_icon_theme_path ()
//
//const gchar * app_indicator_get_icon_theme_path (AppIndicator *self);
// Wrapper function for property "icon-theme-path".
//
// self :
//
// The AppIndicator object to use
// Returns :
//
// The current icon theme path.
// g_param_spec_int ("check-icon-size",
// "Check icon size",
// "Check icon size",
// -1, G_MAXINT, 40,
// G_PARAM_READWRITE));
// -GtkCheckButton-indicator-size: 15;
// -GtkCheckMenuItem-indicator-size: 14;
// GdMainIconView.content-view {
// -GdMainIconView-icon-size: 40;
//}
// no idea? check scaling? base it off of CSS values????
// what about KDE or elementary OS or unix? or arch?
// return 32;
// sane default
return 22;
}