1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-06-07 19:59:14 -04:00

feat(ipc): add powerprofile status & shared profile helpers

- Follow-up to PR #2515
This commit is contained in:
purian23
2026-05-30 14:57:01 -04:00
parent 461da22b08
commit b7daf3f64a
7 changed files with 171 additions and 64 deletions
+63
View File
@@ -282,6 +282,53 @@ dms ipc call inhibit toggle
dms ipc call inhibit enable dms ipc call inhibit enable
``` ```
## Target: `powerprofile`
Power profile control via `power-profiles-daemon`. Changes stay in sync with DMS UI and trigger the power profile OSD when enabled.
Requires `power-profiles-daemon` to be installed and running. Works on all compositors.
### Functions
**`open`**
- Show the power profile picker modal
- Returns: Success confirmation or error if daemon unavailable
**`close`**
- Close the power profile picker modal
- Returns: Success confirmation
**`toggle`**
- Toggle power profile picker modal visibility
- Returns: Success confirmation or error if daemon unavailable
**`list`**
- List available profile slugs, one per line
- Returns: `power-saver`, `balanced`, and `performance` when supported
**`status`**
- Get the currently active profile slug
- Returns: `power-saver`, `balanced`, `performance`, or error if daemon unavailable
**`set <profile>`**
- Set the active power profile
- Parameters: Profile slug or alias — `power-saver` (`powersaver`, `saver`, `0`), `balanced` (`1`), `performance` (`2`)
- Returns: Success confirmation or error if profile unknown, unsupported, or write failed
**`cycle`**
- Cycle to the next available profile in order: power-saver → balanced → performance → power-saver
- Returns: Success confirmation or error if daemon unavailable or write failed
### Examples
```bash
dms ipc call powerprofile status
dms ipc call powerprofile list
dms ipc call powerprofile cycle
dms ipc call powerprofile set balanced
dms ipc call powerprofile set performance
dms ipc call powerprofile toggle
```
## Target: `wallpaper` ## Target: `wallpaper`
Wallpaper management and retrieval with support for per-monitor configurations. Wallpaper management and retrieval with support for per-monitor configurations.
@@ -543,6 +590,18 @@ Power menu modal control for system power actions.
- `close` - Hide power menu modal - `close` - Hide power menu modal
- `toggle` - Toggle power menu modal visibility - `toggle` - Toggle power menu modal visibility
### Target: `powerprofile`
Power profile picker modal and profile control via `power-profiles-daemon`.
**Functions:**
- `open` - Show power profile picker modal
- `close` - Hide power profile picker modal
- `toggle` - Toggle power profile picker modal visibility
- `list` - List available profile slugs
- `status` - Get current profile slug
- `set <profile>` - Set profile by slug or alias (`power-saver`, `balanced`, `performance`)
- `cycle` - Cycle to the next available profile
### Target: `control-center` ### Target: `control-center`
Control Center popout containing network, bluetooth, audio, power, and other quick settings. Control Center popout containing network, bluetooth, audio, power, and other quick settings.
@@ -673,6 +732,10 @@ dms ipc call processlist toggle
# Show power menu # Show power menu
dms ipc call powermenu toggle dms ipc call powermenu toggle
# Cycle or set power profile (requires power-profiles-daemon)
dms ipc call powerprofile cycle
dms ipc call powerprofile toggle
# Open notepad # Open notepad
dms ipc call notepad toggle dms ipc call notepad toggle
+24 -37
View File
@@ -1894,7 +1894,7 @@ Item {
IpcHandler { IpcHandler {
function open(): string { function open(): string {
if (typeof PowerProfiles === "undefined") if (!PowerProfileWatcher.available)
return "ERROR: power-profiles-daemon not available"; return "ERROR: power-profiles-daemon not available";
PopoutService.openPowerProfileModal(); PopoutService.openPowerProfileModal();
@@ -1907,7 +1907,7 @@ Item {
} }
function toggle(): string { function toggle(): string {
if (typeof PowerProfiles === "undefined") if (!PowerProfileWatcher.available)
return "ERROR: power-profiles-daemon not available"; return "ERROR: power-profiles-daemon not available";
PopoutService.togglePowerProfileModal(); PopoutService.togglePowerProfileModal();
@@ -1915,59 +1915,46 @@ Item {
} }
function list(): string { function list(): string {
if (typeof PowerProfiles === "undefined") if (!PowerProfileWatcher.available)
return "ERROR: power-profiles-daemon not available"; return "ERROR: power-profiles-daemon not available";
const profiles = ["power-saver", "balanced"]; return PowerProfileWatcher.availableProfiles.map(profile => PowerProfileWatcher.profileSlug(profile)).join("\n");
if (PowerProfiles.hasPerformanceProfile) }
profiles.push("performance");
return profiles.join("\n"); function status(): string {
if (!PowerProfileWatcher.available)
return "ERROR: power-profiles-daemon not available";
return PowerProfileWatcher.profileSlug(PowerProfiles.profile);
} }
function set(profile: string): string { function set(profile: string): string {
if (typeof PowerProfiles === "undefined") if (!PowerProfileWatcher.available)
return "ERROR: power-profiles-daemon not available"; return "ERROR: power-profiles-daemon not available";
if (!profile) if (!profile)
return "ERROR: No profile specified"; return "ERROR: No profile specified";
const lower = profile.toLowerCase().trim(); const parsed = PowerProfileWatcher.parseProfileSlug(profile);
if (lower === "power-saver" || lower === "powersaver" || lower === "saver" || lower === "0") { if (parsed === -1)
PowerProfiles.profile = PowerProfile.PowerSaver;
return "POWERPROFILE_SET_SUCCESS";
} else if (lower === "balanced" || lower === "1") {
PowerProfiles.profile = PowerProfile.Balanced;
return "POWERPROFILE_SET_SUCCESS";
} else if (lower === "performance" || lower === "2") {
if (PowerProfiles.hasPerformanceProfile) {
PowerProfiles.profile = PowerProfile.Performance;
return "POWERPROFILE_SET_SUCCESS";
} else {
return "ERROR: Performance profile not supported by hardware";
}
} else {
return "ERROR: Unknown power profile. Supported options: power-saver, balanced, performance"; return "ERROR: Unknown power profile. Supported options: power-saver, balanced, performance";
}
if (parsed === PowerProfile.Performance && !PowerProfiles.hasPerformanceProfile)
return "ERROR: Performance profile not supported by hardware";
if (!PowerProfileWatcher.applyProfile(parsed))
return "ERROR: Failed to set power profile";
return "POWERPROFILE_SET_SUCCESS";
} }
function cycle(): string { function cycle(): string {
if (typeof PowerProfiles === "undefined") if (!PowerProfileWatcher.available)
return "ERROR: power-profiles-daemon not available"; return "ERROR: power-profiles-daemon not available";
const current = PowerProfiles.profile; if (!PowerProfileWatcher.cycleProfile())
const profiles = [PowerProfile.PowerSaver, PowerProfile.Balanced]; return "ERROR: Failed to set power profile";
if (PowerProfiles.hasPerformanceProfile)
profiles.push(PowerProfile.Performance);
const index = profiles.indexOf(current);
if (index === -1) {
PowerProfiles.profile = PowerProfile.Balanced;
return "POWERPROFILE_CYCLE_SUCCESS";
}
const nextIndex = (index + 1) % profiles.length;
PowerProfiles.profile = profiles[nextIndex];
return "POWERPROFILE_CYCLE_SUCCESS"; return "POWERPROFILE_CYCLE_SUCCESS";
} }
+9 -4
View File
@@ -12,7 +12,7 @@ DankModal {
keepPopoutsOpen: true keepPopoutsOpen: true
property int selectedIndex: 0 property int selectedIndex: 0
property var profileModel: (typeof PowerProfiles !== "undefined") ? [PowerProfile.PowerSaver, PowerProfile.Balanced].concat(PowerProfiles.hasPerformanceProfile ? [PowerProfile.Performance] : []) : [PowerProfile.PowerSaver, PowerProfile.Balanced, PowerProfile.Performance] property var profileModel: PowerProfileWatcher.availableProfiles
function openCentered() { function openCentered() {
open(); open();
@@ -100,10 +100,15 @@ DankModal {
} }
function setProfile(profile) { function setProfile(profile) {
if (typeof PowerProfiles !== "undefined") { if (PowerProfileWatcher.applyProfile(profile)) {
PowerProfiles.profile = profile;
}
hideDialog(); hideDialog();
return;
}
if (!PowerProfileWatcher.available)
ToastService.showError(I18n.tr("power-profiles-daemon not available"));
else
ToastService.showError(I18n.tr("Failed to set power profile"));
} }
content: Component { content: Component {
@@ -24,15 +24,14 @@ Rectangle {
} }
function setProfile(profile) { function setProfile(profile) {
if (typeof PowerProfiles === "undefined") { if (PowerProfileWatcher.applyProfile(profile))
ToastService.showError(I18n.tr("power-profiles-daemon not available"));
return; return;
}
PowerProfiles.profile = profile; if (!PowerProfileWatcher.available)
if (PowerProfiles.profile !== profile) { ToastService.showError(I18n.tr("power-profiles-daemon not available"));
else
ToastService.showError(I18n.tr("Failed to set power profile")); ToastService.showError(I18n.tr("Failed to set power profile"));
} }
}
Column { Column {
id: contentColumn id: contentColumn
@@ -193,7 +192,7 @@ Rectangle {
} }
DankButtonGroup { DankButtonGroup {
property var profileModel: (typeof PowerProfiles !== "undefined") ? [PowerProfile.PowerSaver, PowerProfile.Balanced].concat(PowerProfiles.hasPerformanceProfile ? [PowerProfile.Performance] : []) : [PowerProfile.PowerSaver, PowerProfile.Balanced, PowerProfile.Performance] property var profileModel: PowerProfileWatcher.availableProfiles
property int currentProfileIndex: { property int currentProfileIndex: {
if (typeof PowerProfiles === "undefined") if (typeof PowerProfiles === "undefined")
return 1; return 1;
@@ -21,15 +21,14 @@ DankPopout {
} }
function setProfile(profile) { function setProfile(profile) {
if (typeof PowerProfiles === "undefined") { if (PowerProfileWatcher.applyProfile(profile))
ToastService.showError(I18n.tr("power-profiles-daemon not available"));
return; return;
}
PowerProfiles.profile = profile; if (!PowerProfileWatcher.available)
if (PowerProfiles.profile !== profile) { ToastService.showError(I18n.tr("power-profiles-daemon not available"));
else
ToastService.showError(I18n.tr("Failed to set power profile")); ToastService.showError(I18n.tr("Failed to set power profile"));
} }
}
popupWidth: 400 popupWidth: 400
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 0 popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 0
@@ -555,7 +554,7 @@ DankPopout {
DankButtonGroup { DankButtonGroup {
id: profileButtonGroup id: profileButtonGroup
property var profileModel: (typeof PowerProfiles !== "undefined") ? [PowerProfile.PowerSaver, PowerProfile.Balanced].concat(PowerProfiles.hasPerformanceProfile ? [PowerProfile.Performance] : []) : [PowerProfile.PowerSaver, PowerProfile.Balanced, PowerProfile.Performance] property var profileModel: PowerProfileWatcher.availableProfiles
property int currentProfileIndex: { property int currentProfileIndex: {
if (typeof PowerProfiles === "undefined") if (typeof PowerProfiles === "undefined")
return 1; return 1;
@@ -140,30 +140,24 @@ BasePill {
log.info("Trigger! Delta: " + delta); log.info("Trigger! Delta: " + delta);
// This is after the other delta checks so it only shows on valid Y scroll // This is after the other delta checks so it only shows on valid Y scroll
if (typeof PowerProfiles === "undefined") { if (!PowerProfileWatcher.available) {
ToastService.showError(I18n.tr("power-profiles-daemon not available")); ToastService.showError(I18n.tr("power-profiles-daemon not available"));
return; return;
} }
// Get list of profiles, and current index const profiles = PowerProfileWatcher.availableProfiles;
const profiles = [PowerProfile.PowerSaver, PowerProfile.Balanced].concat(PowerProfiles.hasPerformanceProfile ? [PowerProfile.Performance] : []);
var index = profiles.findIndex(profile => PowerProfiles.profile === profile); var index = profiles.findIndex(profile => PowerProfiles.profile === profile);
// Step once based on mouse wheel direction
if (delta > 0) if (delta > 0)
index += 1; index += 1;
else else
index -= 1; index -= 1;
// Already at end of list, can't go further
if (index < 0 || index >= profiles.length) if (index < 0 || index >= profiles.length)
return; return;
// Set new profile if (!PowerProfileWatcher.applyProfile(profiles[index]))
PowerProfiles.profile = profiles[index];
if (PowerProfiles.profile !== profiles[index]) {
ToastService.showError(I18n.tr("Failed to set power profile")); ToastService.showError(I18n.tr("Failed to set power profile"));
} }
} }
} }
}
@@ -11,8 +11,68 @@ Singleton {
property int currentProfile: -1 property int currentProfile: -1
property int previousProfile: -1 property int previousProfile: -1
readonly property bool available: typeof PowerProfiles !== "undefined"
readonly property var availableProfiles: {
if (!available)
return [PowerProfile.PowerSaver, PowerProfile.Balanced, PowerProfile.Performance];
return [PowerProfile.PowerSaver, PowerProfile.Balanced].concat(PowerProfiles.hasPerformanceProfile ? [PowerProfile.Performance] : []);
}
signal profileChanged(int profile) signal profileChanged(int profile)
function profileSlug(profile: int): string {
switch (profile) {
case PowerProfile.PowerSaver:
return "power-saver";
case PowerProfile.Balanced:
return "balanced";
case PowerProfile.Performance:
return "performance";
default:
return "unknown";
}
}
function parseProfileSlug(slug: string): int {
if (!slug)
return -1;
const lower = slug.toLowerCase().trim();
if (lower === "power-saver" || lower === "powersaver" || lower === "saver" || lower === "0")
return PowerProfile.PowerSaver;
if (lower === "balanced" || lower === "1")
return PowerProfile.Balanced;
if (lower === "performance" || lower === "2")
return PowerProfile.Performance;
return -1;
}
function applyProfile(profile: int): bool {
if (!available)
return false;
if (profile === PowerProfile.Performance && !PowerProfiles.hasPerformanceProfile)
return false;
if (availableProfiles.indexOf(profile) === -1)
return false;
PowerProfiles.profile = profile;
return PowerProfiles.profile === profile;
}
function cycleProfile(): bool {
if (!available)
return false;
const profiles = availableProfiles;
const index = profiles.indexOf(PowerProfiles.profile);
const nextProfile = index === -1 ? PowerProfile.Balanced : profiles[(index + 1) % profiles.length];
return applyProfile(nextProfile);
}
Connections { Connections {
target: typeof PowerProfiles !== "undefined" ? PowerProfiles : null target: typeof PowerProfiles !== "undefined" ? PowerProfiles : null