forked from Shinonome/dots-hyprland
Feature (Overlay): MangoHud Fps Limiter widget (#2388)
This commit is contained in:
@@ -107,6 +107,12 @@ Singleton {
|
|||||||
property real y: 280
|
property real y: 280
|
||||||
property int tabIndex: 0
|
property int tabIndex: 0
|
||||||
}
|
}
|
||||||
|
property JsonObject fpsLimiter: JsonObject {
|
||||||
|
property bool pinned: false
|
||||||
|
property bool clickthrough: false
|
||||||
|
property real x: 1576
|
||||||
|
property real y: 630
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property JsonObject timer: JsonObject {
|
property JsonObject timer: JsonObject {
|
||||||
|
|||||||
@@ -18,5 +18,6 @@ ToolbarButton {
|
|||||||
iconSize: 22
|
iconSize: 22
|
||||||
text: iconBtn.text
|
text: iconBtn.text
|
||||||
color: iconBtn.colText
|
color: iconBtn.colText
|
||||||
|
animateChange: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ Scope {
|
|||||||
exclusionMode: ExclusionMode.Ignore
|
exclusionMode: ExclusionMode.Ignore
|
||||||
WlrLayershell.namespace: "quickshell:overlay"
|
WlrLayershell.namespace: "quickshell:overlay"
|
||||||
WlrLayershell.layer: WlrLayer.Overlay
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
WlrLayershell.keyboardFocus: GlobalStates.overlayOpen ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
|
||||||
visible: true
|
visible: true
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
@@ -43,6 +43,30 @@ Scope {
|
|||||||
right: true
|
right: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HyprlandFocusGrab {
|
||||||
|
id: grab
|
||||||
|
windows: [overlayWindow]
|
||||||
|
active: false
|
||||||
|
onCleared: () => {
|
||||||
|
if (!active) GlobalStates.overlayOpen = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: GlobalStates
|
||||||
|
function onOverlayOpenChanged() {
|
||||||
|
delayedGrabTimer.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: delayedGrabTimer
|
||||||
|
interval: Appearance.animation.elementMoveFast.duration
|
||||||
|
onTriggered: {
|
||||||
|
grab.active = GlobalStates.overlayOpen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OverlayContent {
|
OverlayContent {
|
||||||
id: overlayContent
|
id: overlayContent
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import qs.modules.overlay.crosshair
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
focus: true
|
||||||
readonly property bool usePasswordChars: !PolkitService.flow?.responseVisible ?? true
|
readonly property bool usePasswordChars: !PolkitService.flow?.responseVisible ?? true
|
||||||
|
|
||||||
Keys.onPressed: (event) => { // Esc to close
|
Keys.onPressed: (event) => { // Esc to close
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ Singleton {
|
|||||||
{ identifier: "recorder", materialSymbol: "screen_record" },
|
{ identifier: "recorder", materialSymbol: "screen_record" },
|
||||||
{ identifier: "volumeMixer", materialSymbol: "volume_up" },
|
{ identifier: "volumeMixer", materialSymbol: "volume_up" },
|
||||||
{ identifier: "crosshair", materialSymbol: "point_scan" },
|
{ identifier: "crosshair", materialSymbol: "point_scan" },
|
||||||
|
{ identifier: "fpsLimiter", materialSymbol: "animation" },
|
||||||
{ identifier: "resources", materialSymbol: "browse_activity" }
|
{ identifier: "resources", materialSymbol: "browse_activity" }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import Quickshell
|
|||||||
import Quickshell.Bluetooth
|
import Quickshell.Bluetooth
|
||||||
import qs.modules.overlay.crosshair
|
import qs.modules.overlay.crosshair
|
||||||
import qs.modules.overlay.volumeMixer
|
import qs.modules.overlay.volumeMixer
|
||||||
|
import qs.modules.overlay.fpsLimiter
|
||||||
import qs.modules.overlay.recorder
|
import qs.modules.overlay.recorder
|
||||||
import qs.modules.overlay.resources
|
import qs.modules.overlay.resources
|
||||||
|
|
||||||
@@ -17,6 +18,7 @@ DelegateChooser {
|
|||||||
|
|
||||||
DelegateChoice { roleValue: "crosshair"; Crosshair {} }
|
DelegateChoice { roleValue: "crosshair"; Crosshair {} }
|
||||||
DelegateChoice { roleValue: "volumeMixer"; VolumeMixer {} }
|
DelegateChoice { roleValue: "volumeMixer"; VolumeMixer {} }
|
||||||
|
DelegateChoice { roleValue: "fpsLimiter"; FpsLimiter {} }
|
||||||
DelegateChoice { roleValue: "recorder"; Recorder {} }
|
DelegateChoice { roleValue: "recorder"; Recorder {} }
|
||||||
DelegateChoice { roleValue: "resources"; Resources {} }
|
DelegateChoice { roleValue: "resources"; Resources {} }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import qs.modules.common
|
||||||
|
import qs.modules.overlay
|
||||||
|
|
||||||
|
StyledOverlayWidget {
|
||||||
|
id: root
|
||||||
|
title: "MangoHud FPS"
|
||||||
|
contentItem: FpsLimiterContent {
|
||||||
|
radius: root.contentRadius
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import qs.services
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import qs.modules.common
|
||||||
|
import qs.modules.common.widgets
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
enum State { Normal, Success, Error }
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
property real padding: 16
|
||||||
|
property var currentState: FpsLimiterContent.State.Normal
|
||||||
|
color: Appearance.m3colors.m3surfaceContainer
|
||||||
|
implicitWidth: content.implicitWidth + (padding * 2)
|
||||||
|
implicitHeight: content.implicitHeight + (padding * 2)
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: iconResetTimer
|
||||||
|
interval: 1000
|
||||||
|
onTriggered: {
|
||||||
|
root.currentState = FpsLimiterContent.State.Normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyLimit() {
|
||||||
|
var fpsValue = parseInt(fpsField.text);
|
||||||
|
if (isNaN(fpsValue) || fpsValue < 0) {
|
||||||
|
root.currentState = FpsLimiterContent.State.Error;
|
||||||
|
iconResetTimer.restart();
|
||||||
|
fpsField.text = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cfgPaths = [
|
||||||
|
"~/.config/MangoHud/MangoHud.conf",
|
||||||
|
]; // MangoHud config files
|
||||||
|
|
||||||
|
var updateCommands = cfgPaths.map(path => {
|
||||||
|
return "if grep -q '^fps_limit=' " + path + "; " +
|
||||||
|
"then sed -i 's/^fps_limit=.*/fps_limit=" + fpsValue + "/' " + path + "; " +
|
||||||
|
"else echo 'fps_limit=" + fpsValue + "' >> " + path + "; fi";
|
||||||
|
}).join("; ");
|
||||||
|
|
||||||
|
var cmd = updateCommands + "; pkill -SIGUSR2 mangohud";
|
||||||
|
|
||||||
|
fpsSetter.command = ["bash", "-c", cmd];
|
||||||
|
fpsSetter.startDetached();
|
||||||
|
|
||||||
|
root.currentState = FpsLimiterContent.State.Success;
|
||||||
|
iconResetTimer.restart();
|
||||||
|
|
||||||
|
// Clear the field after applying
|
||||||
|
fpsField.text = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: fpsSetter
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: content
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 4
|
||||||
|
|
||||||
|
ToolbarTextField {
|
||||||
|
id: fpsField
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredWidth: 200
|
||||||
|
placeholderText: root.currentState === FpsLimiterContent.State.Error ? Translation.tr("Enter a valid number") : Translation.tr("Set FPS limit")
|
||||||
|
inputMethodHints: Qt.ImhDigitsOnly
|
||||||
|
focus: true
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
root.applyLimit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconToolbarButton {
|
||||||
|
id: applyButton
|
||||||
|
text: switch (root.currentState) {
|
||||||
|
case FpsLimiterContent.State.Error: return "close";
|
||||||
|
case FpsLimiterContent.State.Success: return "check";
|
||||||
|
case FpsLimiterContent.State.Normal:
|
||||||
|
default: return "save";
|
||||||
|
}
|
||||||
|
enabled: root.currentState === FpsLimiterContent.State.Normal && fpsField.text.length > 0
|
||||||
|
onClicked: {
|
||||||
|
root.applyLimit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user