Skip to content

Commit 95b86d1

Browse files
committed
feat(dms): Nvidia Optimus Widget for DMS
1 parent ffbbca0 commit 95b86d1

File tree

8 files changed

+276
-1
lines changed

8 files changed

+276
-1
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[General]
2+
no-cmake-calls=true
3+
importPaths="/usr/bin:/usr/lib/qt6/qml:."
4+
buildDir="/run/user/1000/quickshell/vfs/1fcf34aec1908316f4a2099ee8430a19"
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1-
{}
1+
{
2+
"exampleEmojiPlugin": {
3+
"enabled": true
4+
},
5+
"optimusPlugin": {
6+
"enabled": true
7+
}
8+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import QtQuick
2+
import qs.Common
3+
import qs.Widgets
4+
import qs.Modules.Plugins
5+
6+
PluginSettings {
7+
id: root
8+
pluginId: "optimusPlugin"
9+
10+
// Header section
11+
StyledText {
12+
width: parent.width
13+
text: "Optimus GPU Mode Settings"
14+
font.pixelSize: Theme.fontSizeLarge
15+
font.weight: Font.Bold
16+
color: Theme.surfaceText
17+
}
18+
19+
StyledText {
20+
width: parent.width
21+
text: "Monitor and switch GPU modes on your ASUS laptop with MUX switch support."
22+
font.pixelSize: Theme.fontSizeSmall
23+
color: Theme.surfaceVariantText
24+
wrapMode: Text.WordWrap
25+
}
26+
27+
StyledText {
28+
width: parent.width
29+
text: "This plugin displays a color-coded indicator in your bar showing the current GPU mode:"
30+
font.pixelSize: Theme.fontSizeSmall
31+
color: Theme.surfaceVariantText
32+
wrapMode: Text.WordWrap
33+
topPadding: Theme.spacingMedium
34+
}
35+
36+
Column {
37+
width: parent.width
38+
spacing: Theme.spacingXS
39+
leftPadding: Theme.spacingMedium
40+
41+
StyledText {
42+
text: "🔋 Green - Integrated (best battery life)"
43+
font.pixelSize: Theme.fontSizeSmall
44+
color: Theme.surfaceVariantText
45+
}
46+
47+
StyledText {
48+
text: "⚡ Blue - Hybrid (balanced)"
49+
font.pixelSize: Theme.fontSizeSmall
50+
color: Theme.surfaceVariantText
51+
}
52+
53+
StyledText {
54+
text: "🎮 Red - MUX/dGPU Direct (best performance)"
55+
font.pixelSize: Theme.fontSizeSmall
56+
color: Theme.surfaceVariantText
57+
}
58+
}
59+
60+
StyledText {
61+
width: parent.width
62+
text: "💡 Tip: Click the widget in your bar to open the mode selector. Changing modes requires a reboot to take effect."
63+
font.pixelSize: Theme.fontSizeSmall
64+
color: Theme.surfaceVariantText
65+
wrapMode: Text.WordWrap
66+
topPadding: Theme.spacingMedium
67+
}
68+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import QtQuick
2+
import Quickshell
3+
import Quickshell.Io
4+
import qs.Common
5+
import qs.Services
6+
import qs.Widgets
7+
import qs.Modules.Plugins
8+
9+
PluginComponent {
10+
id: root
11+
12+
property string iconName: "bolt"
13+
property bool initialModeLoaded: false
14+
readonly property string currentMode: configFile.text().trim()
15+
readonly property string gpuStatus: gpuStatusFile.text().trim()
16+
17+
function statusColor() {
18+
if (currentMode === "integrated")
19+
return Theme.success;
20+
else if (currentMode === "ultimate")
21+
return Theme.error;
22+
else if (currentMode === "hybrid" && gpuStatus !== "suspended")
23+
return Theme.warning;
24+
else
25+
return Theme.primary;
26+
}
27+
28+
FileView {
29+
id: configFile
30+
path: "/etc/optimus.conf"
31+
watchChanges: true
32+
blockLoading: true
33+
onFileChanged: this.reload()
34+
}
35+
36+
FileView {
37+
id: gpuStatusFile
38+
path: "/sys/class/drm/card0/device/power/runtime_status"
39+
blockLoading: true
40+
}
41+
42+
Timer {
43+
interval: 3000 // 3 seconds
44+
running: true
45+
repeat: true
46+
onTriggered: gpuStatusFile.reload()
47+
}
48+
49+
// onGpuStatusChanged: {
50+
// ToastService.showInfo("dGPU status: " + gpuStatus);
51+
// }
52+
53+
onCurrentModeChanged: {
54+
if (!initialModeLoaded) {
55+
initialModeLoaded = true;
56+
return;
57+
}
58+
const modeLabel = currentMode.toUpperCase().charAt(0) + currentMode.slice(1);
59+
ToastService.showInfo("GPU mode set to " + modeLabel + "\nReboot required to apply");
60+
}
61+
62+
function setMode(mode) {
63+
Quickshell.execDetached(["sh", "-c", "optimus " + mode]);
64+
}
65+
66+
horizontalBarPill: Component {
67+
DankIcon {
68+
name: root.iconName
69+
size: Theme.barIconSize(barThickness)
70+
color: statusColor()
71+
anchors.centerIn: parent
72+
filled: true
73+
}
74+
}
75+
76+
verticalBarPill: horizontalBarPill
77+
78+
popoutContent: Component {
79+
PopoutComponent {
80+
id: popout
81+
82+
headerText: "Optimus Mode"
83+
showCloseButton: true
84+
85+
Column {
86+
width: parent.width
87+
spacing: Theme.spacingMedium
88+
padding: Theme.spacingMedium
89+
90+
DankButtonGroup {
91+
property var modeModel: ["integrated", "hybrid", "ultimate"]
92+
93+
model: ["Integrated", "Hybrid", "Ultimate"]
94+
currentIndex: modeModel.indexOf(root.currentMode)
95+
selectionMode: "single"
96+
anchors.horizontalCenter: parent.horizontalCenter
97+
onSelectionChanged: (index, selected) => {
98+
if (!selected)
99+
return;
100+
root.setMode(modeModel[index]);
101+
popout.closePopout();
102+
}
103+
}
104+
}
105+
}
106+
}
107+
108+
popoutWidth: 400
109+
popoutHeight: 100
110+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Optimus GPU Mode Plugin
2+
3+
A DankMaterialShell plugin for managing GPU modes on ASUS laptops with MUX switch support.
4+
5+
## Features
6+
7+
- **Visual Status Indicator**: Color-coded bar widget showing current GPU mode
8+
- 🔋 Green - Integrated (best battery life)
9+
- ⚡ Blue - Hybrid (balanced)
10+
- 🎮 Red - MUX/dGPU Direct (best performance)
11+
- **Quick Mode Switching**: Click to open mode selector with three options
12+
- **Desktop Notifications**: Shows toast notification when mode is changed
13+
- **Pending Mode Display**: Shows configured mode if different from current (requires reboot)
14+
- **Auto-refresh**: Updates status every 30 seconds
15+
16+
## Installation
17+
18+
1. This plugin should already be installed in `~/.config/DankMaterialShell/plugins/OptimusPlugin`
19+
2. Open DMS Settings → Plugins
20+
3. Click "Scan for Plugins"
21+
4. Enable "Optimus GPU Mode"
22+
5. Add `optimusPlugin` to your DankBar widget list (right side recommended)
23+
24+
## Requirements
25+
26+
- `optimus` command in PATH (from ~/dot/bin/optimus)
27+
- ASUS laptop with MUX switch support
28+
- asusd service running
29+
30+
## GPU Modes
31+
32+
### Integrated (🔋)
33+
- iGPU only, dGPU powered off
34+
- Best for battery life
35+
- Lowest power consumption
36+
37+
### Hybrid (⚡)
38+
- Both GPUs active
39+
- iGPU for display, dGPU for rendering
40+
- Use `prime-run` for GPU-accelerated apps
41+
- Balanced performance and battery
42+
43+
### MUX / dGPU Direct (🎮)
44+
- dGPU directly connected to display
45+
- Best gaming performance
46+
- Highest power consumption
47+
- Requires reboot to switch
48+
49+
## Usage
50+
51+
**In the bar**: View current mode and status color
52+
**Click the widget**: Opens mode selector
53+
**Click a mode**: Sets the mode and shows notification (reboot required)
54+
55+
## Configuration
56+
57+
The widget updates automatically from the `optimus` command output. Configure mode persistence through the systemd service.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"id": "optimusPlugin",
3+
"name": "Optimus GPU Mode",
4+
"description": "Monitor and switch GPU modes on ASUS laptops with MUX switch support",
5+
"version": "1.0.0",
6+
"author": "Folke Lemaitre",
7+
"icon": "memory",
8+
"component": "./OptimusWidget.qml",
9+
"settings": "./OptimusSettings.qml",
10+
"permissions": ["settings_read", "settings_write"]
11+
}

config/DankMaterialShell/settings.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@
137137
},
138138
{
139139
"id": "cpuUsage",
140+
"enabled": true,
141+
"minimumWidth": false
142+
},
143+
{
144+
"id": "optimusPlugin",
140145
"enabled": true
141146
},
142147
{
@@ -170,6 +175,10 @@
170175
"notepadShowLineNumbers": false,
171176
"notepadTransparencyOverride": -1,
172177
"notepadLastCustomTransparency": 0.95,
178+
"soundsEnabled": true,
179+
"soundNewNotification": true,
180+
"soundVolumeChanged": true,
181+
"soundPluggedIn": true,
173182
"gtkThemingEnabled": false,
174183
"qtThemingEnabled": false,
175184
"showDock": false,
@@ -194,6 +203,8 @@
194203
"dankBarBorderColor": "surfaceText",
195204
"dankBarBorderOpacity": 1,
196205
"dankBarBorderThickness": 1,
206+
"popupGapsAuto": true,
207+
"popupGapsManual": 4,
197208
"dankBarPosition": 0,
198209
"lockScreenShowPowerActions": true,
199210
"hideBrightnessSlider": false,
@@ -204,6 +215,9 @@
204215
"notificationTimeoutCritical": 0,
205216
"notificationPopupPosition": 0,
206217
"osdAlwaysShowValue": false,
218+
"updaterUseCustomCommand": false,
219+
"updaterCustomCommand": "",
220+
"updaterTerminalAdditionalParams": "",
207221
"screenPreferences": {},
208222
"animationSpeed": 2
209223
}

nvim/lua/plugins/lsp.lua

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ return {
1313
},
1414
},
1515
servers = {
16+
qmlls = {
17+
cmd = { "qmlls6" },
18+
root_markers = { ".qmlls.ini" },
19+
},
1620
lua_ls = {
1721
-- cmd = { "/home/folke/projects/lua-language-server/bin/lua-language-server" },
1822
-- single_file_support = true,

0 commit comments

Comments
 (0)