GTK: Memory Settings
This commit is contained in:
parent
5c9ce78ebf
commit
eb9601d6cf
|
@ -5,8 +5,7 @@ import org.gtk.gtk.*;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.PropertyKey;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.IntConsumer;
|
||||
import java.util.function.*;
|
||||
|
||||
public class IRow extends Box {
|
||||
public IRow(@PropertyKey(resourceBundle = I18n.BUNDLE) String title, @PropertyKey(resourceBundle = I18n.BUNDLE) @Nullable String subtitle, Object... args) {
|
||||
|
@ -30,51 +29,58 @@ public class IRow extends Box {
|
|||
append(head);
|
||||
}
|
||||
|
||||
public void setButton(@PropertyKey(resourceBundle = I18n.BUNDLE) String text, Button.Clicked action) {
|
||||
firstChild.hexpand = true;
|
||||
public Button setButton(@PropertyKey(resourceBundle = I18n.BUNDLE) String text, Button.Clicked action) {
|
||||
Button btn = Button.newWithLabel(I18n.get(text));
|
||||
btn.valign = Align.CENTER;
|
||||
btn.halign = Align.END;
|
||||
packSmallEnd(btn);
|
||||
btn.onClicked(action);
|
||||
append(btn);
|
||||
return btn;
|
||||
}
|
||||
|
||||
public DropDown setDropdown(String[] options, int defaultIndex, IntConsumer changed) {
|
||||
firstChild.hexpand = true;
|
||||
DropDown btn = new DropDown(new StringList(options), null);
|
||||
btn.valign = Align.CENTER;
|
||||
btn.halign = Align.END;
|
||||
packSmallEnd(btn);
|
||||
btn.selected = defaultIndex;
|
||||
btn.onNotify("selected", pspec -> {
|
||||
changed.accept(btn.selected);
|
||||
});
|
||||
btn.expression = new PropertyExpression(StringObject.type, null, "string");
|
||||
append(btn);
|
||||
return btn;
|
||||
}
|
||||
|
||||
public Switch setCheckbox(boolean value, Consumer<Boolean> changed) {
|
||||
firstChild.hexpand = true;
|
||||
public Switch setSwitch(boolean value, Consumer<Boolean> changed) {
|
||||
Switch btn = new Switch();
|
||||
btn.valign = Align.CENTER;
|
||||
btn.halign = Align.END;
|
||||
packSmallEnd(btn);
|
||||
btn.active = value;
|
||||
btn.onStateSet(state -> {
|
||||
changed.accept(state);
|
||||
return false;
|
||||
});
|
||||
append(btn);
|
||||
return btn;
|
||||
}
|
||||
|
||||
public Entry setEntry(String value, Consumer<String> onChanged) {
|
||||
public SpinButton setSpinButton(double value, double min, double max, double step, DoubleConsumer changed) {
|
||||
SpinButton btn = SpinButton.newWithRange(min, max, step);
|
||||
packSmallEnd(btn);
|
||||
btn.value = value;
|
||||
btn.onValueChanged(() -> changed.accept(btn.value));
|
||||
return btn;
|
||||
}
|
||||
|
||||
public Entry setEntry(String value, Consumer<String> changed) {
|
||||
Entry entry = new Entry();
|
||||
entry.text = value == null ? "" : value;
|
||||
entry.hexpand = true;
|
||||
entry.valign = Align.CENTER;
|
||||
entry.halign = Align.FILL;
|
||||
entry.onChanged(() -> onChanged.accept(entry.text));
|
||||
entry.onChanged(() -> changed.accept(entry.text));
|
||||
append(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
private void packSmallEnd(Widget widget) {
|
||||
firstChild.hexpand = true;
|
||||
widget.valign = Align.CENTER;
|
||||
widget.halign = Align.END;
|
||||
append(widget);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
package io.gitlab.jfronny.inceptum.gtk.util;
|
||||
|
||||
import io.gitlab.jfronny.commons.LazySupplier;
|
||||
import io.gitlab.jfronny.commons.OSUtils;
|
||||
import io.gitlab.jfronny.inceptum.common.Utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Memory {
|
||||
public static final long KB = 1024;
|
||||
public static final long MB = KB * 1024;
|
||||
public static final long GB = MB * 1024;
|
||||
private static final MI impl = switch (OSUtils.TYPE) {
|
||||
case LINUX -> new LinuxMI();
|
||||
case WINDOWS -> new WindowsMI();
|
||||
case MAC_OS -> new MacOsMI();
|
||||
};
|
||||
|
||||
private static final LazySupplier<Long> totalMemory = new LazySupplier<>(impl::getTotalMemory);
|
||||
|
||||
public static long getMaxMBForInstance() {
|
||||
return Math.max(totalMemory.get() / MB - 1024, 1024);
|
||||
}
|
||||
|
||||
private interface MI {
|
||||
long getTotalMemory();
|
||||
}
|
||||
|
||||
private static class LinuxMI implements MI {
|
||||
@Override
|
||||
public long getTotalMemory() {
|
||||
try (Stream<String> stream = Files.lines(Path.of("/proc/meminfo"))) {
|
||||
var memTotal = stream
|
||||
.filter(s -> s.startsWith("MemTotal:"))
|
||||
.map(s -> s.substring("MemTotal:".length()))
|
||||
.map(String::trim)
|
||||
.findFirst();
|
||||
if (memTotal.isPresent()) {
|
||||
return parseDecimalMemorySizeToBinary(memTotal.get());
|
||||
} else {
|
||||
Utils.LOGGER.error("Could not find total memory");
|
||||
return 32 * GB;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Utils.LOGGER.error("Could not get total memory", e);
|
||||
return 32 * GB;
|
||||
}
|
||||
}
|
||||
|
||||
// Taken from oshi
|
||||
private static final Pattern BYTES_PATTERN = Pattern.compile("(\\d+) ?([kKMGT]?B?).*");
|
||||
private static final Pattern WHITESPACES = Pattern.compile("\\s+");
|
||||
private static long parseDecimalMemorySizeToBinary(String size) {
|
||||
String[] mem = WHITESPACES.split(size);
|
||||
if (mem.length < 2) {
|
||||
// If no spaces, use regexp
|
||||
Matcher matcher = BYTES_PATTERN.matcher(size.trim());
|
||||
if (matcher.find() && matcher.groupCount() == 2) {
|
||||
mem = new String[2];
|
||||
mem[0] = matcher.group(1);
|
||||
mem[1] = matcher.group(2);
|
||||
}
|
||||
}
|
||||
long capacity = parseLongOrDefault(mem[0], 0L);
|
||||
if (mem.length == 2 && mem[1].length() > 1) {
|
||||
switch (mem[1].charAt(0)) {
|
||||
case 'T' -> capacity <<= 40;
|
||||
case 'G' -> capacity <<= 30;
|
||||
case 'M' -> capacity <<= 20;
|
||||
case 'K', 'k' -> capacity <<= 10;
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
return capacity;
|
||||
}
|
||||
private static long parseLongOrDefault(String s, long defaultLong) {
|
||||
try {
|
||||
return Long.parseLong(s);
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultLong;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class WindowsMI implements MI {
|
||||
@Override
|
||||
public long getTotalMemory() {
|
||||
return 32 * GB; // This is currently unsupported, but any implementations by Windows user using panama are welcome
|
||||
}
|
||||
}
|
||||
|
||||
private static class MacOsMI implements MI {
|
||||
@Override
|
||||
public long getTotalMemory() {
|
||||
return 32 * GB; // This is currently unsupported, but any implementations by MacOS user using panama are welcome
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ public class LauncherSettingsWindow extends Window {
|
|||
{
|
||||
IRow row = new IRow("settings.snapshots", "settings.snapshots.subtitle");
|
||||
listBox.append(row);
|
||||
row.setCheckbox(InceptumConfig.snapshots, b -> {
|
||||
row.setSwitch(InceptumConfig.snapshots, b -> {
|
||||
InceptumConfig.snapshots = b;
|
||||
InceptumConfig.saveConfig();
|
||||
});
|
||||
|
|
|
@ -2,11 +2,11 @@ package io.gitlab.jfronny.inceptum.gtk.window.edit;
|
|||
|
||||
import io.github.jwharm.javagi.GErrorException;
|
||||
import io.gitlab.jfronny.commons.ArgumentsTokenizer;
|
||||
import io.gitlab.jfronny.commons.OSUtils;
|
||||
import io.gitlab.jfronny.commons.io.JFiles;
|
||||
import io.gitlab.jfronny.inceptum.common.*;
|
||||
import io.gitlab.jfronny.inceptum.gtk.control.ILabel;
|
||||
import io.gitlab.jfronny.inceptum.gtk.util.I18n;
|
||||
import io.gitlab.jfronny.inceptum.gtk.util.Memory;
|
||||
import io.gitlab.jfronny.inceptum.gtk.window.InstanceSettingsWindow;
|
||||
import io.gitlab.jfronny.inceptum.launcher.api.FabricMetaApi;
|
||||
import io.gitlab.jfronny.inceptum.launcher.api.McApi;
|
||||
|
@ -78,7 +78,7 @@ public class GeneralTab extends SettingsTab {
|
|||
var fabricRow = section.row("instance.settings.general.game.fabric.enabled", "instance.settings.general.game.fabric.enabled.subtitle");
|
||||
var loaderRow = section.row("instance.settings.general.game.fabric.version", "instance.settings.general.game.fabric.version.subtitle");
|
||||
loaderRow.visible = instance.isFabric;
|
||||
ref.fabricEnabled = fabricRow.setCheckbox(instance.isFabric, bl -> {
|
||||
ref.fabricEnabled = fabricRow.setSwitch(instance.isFabric, bl -> {
|
||||
if (bl) {
|
||||
if (ref.fabricVersions != null && ref.fabricVersions.length != 0 && ref.defaultFabric != null) {
|
||||
instance.meta.gameVersion = GameVersionParser.createVersionWithFabric(instance.gameVersion, ref.defaultFabric);
|
||||
|
@ -151,7 +151,22 @@ public class GeneralTab extends SettingsTab {
|
|||
});
|
||||
row.append(btn);
|
||||
}
|
||||
//TODO minMem/maxMem (slider?)
|
||||
{
|
||||
var row = section.row("instance.settings.general.game.memory.min", "instance.settings.general.game.memory.min.subtitle");
|
||||
row.setSpinButton(instance.meta.minMem == null ? 512 : instance.meta.minMem / Memory.MB, 512, Memory.maxMBForInstance, 128, v -> {
|
||||
instance.meta.minMem = (long) (v * Memory.MB);
|
||||
if (instance.meta.minMem == Memory.GB / 2) instance.meta.minMem = null;
|
||||
instance.writeMeta();
|
||||
});
|
||||
}
|
||||
{
|
||||
var row = section.row("instance.settings.general.game.memory.max", "instance.settings.general.game.memory.max.subtitle");
|
||||
row.setSpinButton(instance.meta.maxMem == null ? 1024 : instance.meta.maxMem / Memory.MB, 1024, Memory.maxMBForInstance, 128, v -> {
|
||||
instance.meta.maxMem = (long) (v * Memory.MB);
|
||||
if (instance.meta.maxMem == Memory.GB) instance.meta.maxMem = null;
|
||||
instance.writeMeta();
|
||||
});
|
||||
}
|
||||
});
|
||||
section("instance.settings.general.args", section -> {
|
||||
if (instance.meta.arguments == null) instance.meta.arguments = new InstanceMeta.Arguments(List.of(), List.of(), List.of());
|
||||
|
|
|
@ -90,4 +90,8 @@ instance.settings.general.game.fabric.enabled.subtitle=Whether the Fabric Loader
|
|||
instance.settings.general.game.fabric.version=Fabric Version
|
||||
instance.settings.general.game.fabric.version.subtitle=Version of the Fabric Loader to use
|
||||
instance.settings.general.game.java=Java
|
||||
instance.settings.general.game.java.subtitle=The path of the custom Java binary to use (or empty for default)
|
||||
instance.settings.general.game.java.subtitle=The path of the custom Java binary to use (or empty for default)
|
||||
instance.settings.general.game.memory.min=Minimum Memory
|
||||
instance.settings.general.game.memory.min.subtitle=The minimum amount of Memory Minecraft will allocate (in MiB)
|
||||
instance.settings.general.game.memory.max=Maximum Memory
|
||||
instance.settings.general.game.memory.max.subtitle=The maximum amount of Memory Minecraft will allocate (in MiB)
|
|
@ -90,4 +90,8 @@ instance.settings.general.game.fabric.enabled.subtitle=Ob Fabric-Loader f
|
|||
instance.settings.general.game.fabric.version=Fabric-Version
|
||||
instance.settings.general.game.fabric.version.subtitle=Zu verwendende Version des Fabric-Loaders
|
||||
instance.settings.general.game.java=Java
|
||||
instance.settings.general.game.java.subtitle=Pfad der Java-Binärdatei, die diese Instanz verwenden soll. Leer lassen um die Standard-Binärdatei zu nutzen.
|
||||
instance.settings.general.game.java.subtitle=Pfad der Java-Binärdatei, die diese Instanz verwenden soll. Leer lassen um die Standard-Binärdatei zu nutzen.
|
||||
instance.settings.general.game.memory.min=Minimale Speichernutzung
|
||||
instance.settings.general.game.memory.min.subtitle=Die minimale Speichernutzung dieser Instanz (in MiB)
|
||||
instance.settings.general.game.memory.max=Maximale Speichernutzung
|
||||
instance.settings.general.game.memory.max.subtitle=Die maximale Speichernutzung dieser Instanz (in MiB)
|
Loading…
Reference in New Issue