Files

327 lines
9.0 KiB
QML

pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Commons
import qs.Services.Power
import qs.Services.Theming
import qs.Services.UI
Singleton {
id: root
// Hook connections for automatic script execution
Connections {
target: Settings.data.colorSchemes
function onDarkModeChanged() {
executeDarkModeHook(Settings.data.colorSchemes.darkMode);
}
}
// Pending wallpaper hook when waiting for color generation
property var pendingWallpaperHook: null
Connections {
target: WallpaperService
function onWallpaperChanged(screenName, path) {
// Check if we need to wait for color generation
if (Settings.data.colorSchemes.useWallpaperColors) {
var effectiveMonitor = Settings.data.colorSchemes.monitorForColors;
if (effectiveMonitor === "" || effectiveMonitor === undefined) {
effectiveMonitor = Screen.name;
}
if (screenName === effectiveMonitor) {
// Store pending hook and wait for colors to be generated
root.pendingWallpaperHook = {
path: path,
screenName: screenName
};
return;
}
}
// No color generation, execute immediately
executeWallpaperHook(path, screenName);
}
}
Connections {
target: TemplateProcessor
function onColorsGenerated() {
// Execute pending wallpaper hook after colors are ready
if (root.pendingWallpaperHook) {
const hook = root.pendingWallpaperHook;
root.pendingWallpaperHook = null;
executeWallpaperHook(hook.path, hook.screenName);
}
executeColorGenerationHook();
}
}
// Track lock screen state for unlock hook
property bool wasLocked: false
Connections {
target: PanelService
function onLockScreenChanged() {
if (PanelService.lockScreen) {
lockScreenActiveConnection.target = PanelService.lockScreen;
}
}
}
Connections {
id: lockScreenActiveConnection
target: PanelService.lockScreen
function onActiveChanged() {
// Detect lock: was unlocked, now locked
if (!wasLocked && PanelService.lockScreen.active) {
executeLockHook();
}
// Detect unlock: was locked, now not locked
if (wasLocked && !PanelService.lockScreen.active) {
executeUnlockHook();
}
wasLocked = PanelService.lockScreen.active;
}
}
// Track performance mode state for hooks
property bool wasPerformanceModeEnabled: false
Connections {
target: PowerProfileService
function onNoctaliaPerformanceModeChanged() {
const isEnabled = PowerProfileService.noctaliaPerformanceMode;
// Detect enabled: was disabled, now enabled
if (!wasPerformanceModeEnabled && isEnabled) {
executePerformanceModeEnabledHook();
}
// Detect disabled: was enabled, now disabled
if (wasPerformanceModeEnabled && !isEnabled) {
executePerformanceModeDisabledHook();
}
wasPerformanceModeEnabled = isEnabled;
}
}
// Execute wallpaper change hook
function executeWallpaperHook(wallpaperPath, screenName) {
if (!Settings.data.hooks?.enabled) {
return;
}
const script = Settings.data.hooks?.wallpaperChange;
if (!script || script === "") {
return;
}
try {
const theme = Settings.data.colorSchemes.darkMode ? "dark" : "light";
let command = script.replace(/\$1/g, wallpaperPath);
command = command.replace(/\$2/g, screenName || "");
command = command.replace(/\$3/g, theme);
Quickshell.execDetached(["sh", "-lc", command]);
Logger.d("HooksService", `Executed wallpaper hook: ${command}`);
} catch (e) {
Logger.e("HooksService", `Failed to execute wallpaper hook: ${e}`);
}
}
// Execute dark mode change hook
function executeDarkModeHook(isDarkMode) {
if (!Settings.data.hooks?.enabled) {
return;
}
const script = Settings.data.hooks?.darkModeChange;
if (!script || script === "") {
return;
}
try {
const command = script.replace(/\$1/g, isDarkMode ? "true" : "false");
Quickshell.execDetached(["sh", "-lc", command]);
Logger.d("HooksService", `Executed dark mode hook: ${command}`);
} catch (e) {
Logger.e("HooksService", `Failed to execute dark mode hook: ${e}`);
}
}
// Execute screen lock hook
function executeLockHook() {
if (!Settings.data.hooks?.enabled) {
return;
}
const script = Settings.data.hooks?.screenLock;
if (!script || script === "") {
return;
}
try {
// Pass "lock" as $1 via shell arguments so the script receives it
Quickshell.execDetached(["sh", "-lc", script, "lock-hook", "lock"]);
Logger.d("HooksService", `Executed screen lock hook: ${script}`);
} catch (e) {
Logger.e("HooksService", `Failed to execute screen lock hook: ${e}`);
}
}
// Execute screen unlock hook
function executeUnlockHook() {
if (!Settings.data.hooks?.enabled) {
return;
}
const script = Settings.data.hooks?.screenUnlock;
if (!script || script === "") {
return;
}
try {
// Pass "unlock" as $1 via shell arguments so the script receives it
Quickshell.execDetached(["sh", "-lc", script, "unlock-hook", "unlock"]);
Logger.d("HooksService", `Executed screen unlock hook: ${script}`);
} catch (e) {
Logger.e("HooksService", `Failed to execute screen unlock hook: ${e}`);
}
}
// Execute performance mode enabled hook
function executePerformanceModeEnabledHook() {
if (!Settings.data.hooks?.enabled) {
return;
}
const script = Settings.data.hooks?.performanceModeEnabled;
if (!script || script === "") {
return;
}
try {
Quickshell.execDetached(["sh", "-lc", script]);
} catch (e) {
Logger.e("HooksService", `Failed to execute performance mode enabled hook: ${e}`);
}
}
// Execute performance mode disabled hook
function executePerformanceModeDisabledHook() {
if (!Settings.data.hooks?.enabled) {
return;
}
const script = Settings.data.hooks?.performanceModeDisabled;
if (!script || script === "") {
return;
}
try {
Quickshell.execDetached(["sh", "-lc", script]);
} catch (e) {
Logger.e("HooksService", `Failed to execute performance mode disabled hook: ${e}`);
}
}
// Execute color generation hook
function executeColorGenerationHook() {
if (!Settings.data.hooks?.enabled) {
return;
}
const script = Settings.data.hooks?.colorGeneration;
if (!script || script === "") {
return;
}
try {
const theme = Settings.data.colorSchemes.darkMode ? "dark" : "light";
const command = script.replace(/\$1/g, theme);
Quickshell.execDetached(["sh", "-lc", command]);
Logger.d("HooksService", `Executed color generation hook: ${command}`);
} catch (e) {
Logger.e("HooksService", `Failed to execute color generation hook: ${e}`);
}
}
// Blocking power hook infrastructure
property var pendingPowerCallback: null
Process {
id: powerHookProcess
onExited: (exitCode, exitStatus) => {
if (exitCode !== 0) {
Logger.w("HooksService", `Power hook failed with exit code ${exitCode}`);
}
if (pendingPowerCallback !== null) {
const callback = pendingPowerCallback;
pendingPowerCallback = null;
callback();
}
}
}
function runPowerHook(script, callback) {
pendingPowerCallback = callback;
powerHookProcess.command = ["sh", "-lc", script];
powerHookProcess.running = true;
}
function executeSessionHook(action, callback) {
if (!Settings.data.hooks?.enabled) {
callback();
return;
}
const script = Settings.data.hooks?.session;
if (!script) {
callback();
return;
}
Logger.i("HooksService", `Executing session hook for ${action}`);
runPowerHook(`${script} ${action}`, callback);
}
// Execute startup hook
function executeStartupHook() {
if (!Settings.data.hooks?.enabled) {
return;
}
const script = Settings.data.hooks?.startup;
if (!script || script === "") {
return;
}
try {
Quickshell.execDetached(["sh", "-lc", script]);
Logger.d("HooksService", `Executed startup hook: ${script}`);
} catch (e) {
Logger.e("HooksService", `Failed to execute startup hook: ${e}`);
}
}
// Initialize the service
function init() {
Logger.i("HooksService", "Service started");
// Initialize lock screen state tracking
Qt.callLater(() => {
if (PanelService.lockScreen) {
wasLocked = PanelService.lockScreen.active;
lockScreenActiveConnection.target = PanelService.lockScreen;
}
// Initialize performance mode state tracking
wasPerformanceModeEnabled = PowerProfileService.noctaliaPerformanceMode;
// Execute startup hook
executeStartupHook();
});
}
}