diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json index 957819178..f5756f516 100644 --- a/Assets/Translations/de.json +++ b/Assets/Translations/de.json @@ -1642,6 +1642,16 @@ "description": "Befehl, der ausgeführt wird, wenn sich das Hintergrundbild ändert.", "label": "Hintergrundbild geändert", "placeholder": "z.B. notify-send \"Hintergrundbild\" \"Geändert\"" + }, + "screen-lock": { + "description": "Befehl, der ausgeführt wird, wenn der Bildschirm gesperrt wird.", + "label": "Bildschirm gesperrt", + "placeholder": "z.B. notify-send \"Bildschirm\" \"Gesperrt\"" + }, + "screen-unlock": { + "description": "Befehl, der ausgeführt wird, wenn der Bildschirm entsperrt wird.", + "label": "Bildschirm entsperrt", + "placeholder": "z.B. notify-send \"Bildschirm\" \"Entsperrt\"" } }, "launcher": { diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index e63fc6afc..3b5ecd4c6 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -1618,7 +1618,7 @@ "label": "Hook command information" }, "parameters": { - "description": "• Wallpaper hook: $1 = wallpaper path, $2 = screen name
• Theme toggle hook: $1 = true/false (Dark Mode state)", + "description": "• Wallpaper hook: $1 = wallpaper path, $2 = screen name
• Theme toggle hook: $1 = true/false (Dark Mode state)
• Screen lock/unlock hooks: No parameters", "label": "Available parameters" } }, @@ -1642,6 +1642,16 @@ "description": "Command to be executed when wallpaper changes.", "label": "Wallpaper changed", "placeholder": "e.g., notify-send \"Wallpaper\" \"Changed\"" + }, + "screen-lock": { + "description": "Command to be executed when the screen is locked.", + "label": "Screen locked", + "placeholder": "e.g., notify-send \"Screen\" \"Locked\"" + }, + "screen-unlock": { + "description": "Command to be executed when the lock screen is unlocked.", + "label": "Screen unlocked", + "placeholder": "e.g., notify-send \"Screen\" \"Unlocked\"" } }, "launcher": { diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index ddaaeed9a..ed5e1036c 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -1642,6 +1642,16 @@ "description": "Comando a ejecutar cuando cambia el fondo de pantalla.", "label": "Fondo de pantalla cambiado", "placeholder": "ej., notify-send \"Fondo de pantalla\" \"Cambiado\"" + }, + "screen-lock": { + "description": "Comando a ejecutar cuando se bloquea la pantalla.", + "label": "Pantalla bloqueada", + "placeholder": "ej., notify-send \"Pantalla\" \"Bloqueada\"" + }, + "screen-unlock": { + "description": "Comando a ejecutar cuando se desbloquea la pantalla.", + "label": "Pantalla desbloqueada", + "placeholder": "ej., notify-send \"Pantalla\" \"Desbloqueada\"" } }, "launcher": { diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json index 546d7f329..3dfccf7c9 100644 --- a/Assets/Translations/fr.json +++ b/Assets/Translations/fr.json @@ -1642,6 +1642,16 @@ "description": "Commande à exécuter lorsque le fond d'écran change.", "label": "Fond d'écran changé", "placeholder": "ex: notify-send \"Fond d'écran\" \"Changé\"" + }, + "screen-lock": { + "description": "Commande à exécuter lorsque l'écran est verrouillé.", + "label": "Écran verrouillé", + "placeholder": "ex: notify-send \"Écran\" \"Verrouillé\"" + }, + "screen-unlock": { + "description": "Commande à exécuter lorsque l'écran est déverrouillé.", + "label": "Écran déverrouillé", + "placeholder": "ex: notify-send \"Écran\" \"Déverrouillé\"" } }, "launcher": { diff --git a/Assets/Translations/ja.json b/Assets/Translations/ja.json index 1dd46e8e1..c52820282 100644 --- a/Assets/Translations/ja.json +++ b/Assets/Translations/ja.json @@ -1642,6 +1642,16 @@ "description": "壁紙が変更された際に実行されるコマンド。", "label": "壁紙変更時", "placeholder": "例: notify-send \"Wallpaper\" \"Changed\"" + }, + "screen-lock": { + "description": "画面がロックされた際に実行されるコマンド。", + "label": "画面ロック時", + "placeholder": "例: notify-send \"Screen\" \"Locked\"" + }, + "screen-unlock": { + "description": "ロック画面が解除された際に実行されるコマンド。", + "label": "画面ロック解除時", + "placeholder": "例: notify-send \"Screen\" \"Unlocked\"" } }, "launcher": { diff --git a/Assets/Translations/nl.json b/Assets/Translations/nl.json index d5e001cf8..520f4a42f 100644 --- a/Assets/Translations/nl.json +++ b/Assets/Translations/nl.json @@ -1642,6 +1642,16 @@ "description": "Commando dat wordt uitgevoerd wanneer de achtergrond verandert.", "label": "Achtergrond gewijzigd", "placeholder": "bijv. notify-send \"Achtergrond\" \"Gewijzigd\"" + }, + "screen-lock": { + "description": "Commando dat wordt uitgevoerd wanneer het scherm wordt vergrendeld.", + "label": "Scherm vergrendeld", + "placeholder": "bijv. notify-send \"Scherm\" \"Vergrendeld\"" + }, + "screen-unlock": { + "description": "Commando dat wordt uitgevoerd wanneer het scherm wordt ontgrendeld.", + "label": "Scherm ontgrendeld", + "placeholder": "bijv. notify-send \"Scherm\" \"Ontgrendeld\"" } }, "launcher": { diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json index 824c00ba8..90ad25276 100644 --- a/Assets/Translations/pt.json +++ b/Assets/Translations/pt.json @@ -1642,6 +1642,16 @@ "description": "Comando a ser executado quando o papel de parede muda.", "label": "Papel de parede alterado", "placeholder": "ex., notify-send \"Papel de parede\" \"Alterado\"" + }, + "screen-lock": { + "description": "Comando a ser executado quando a tela é bloqueada.", + "label": "Tela bloqueada", + "placeholder": "ex., notify-send \"Tela\" \"Bloqueada\"" + }, + "screen-unlock": { + "description": "Comando a ser executado quando a tela é desbloqueada.", + "label": "Tela desbloqueada", + "placeholder": "ex., notify-send \"Tela\" \"Desbloqueada\"" } }, "launcher": { diff --git a/Assets/Translations/ru.json b/Assets/Translations/ru.json index 46d24b19f..69e662f1d 100644 --- a/Assets/Translations/ru.json +++ b/Assets/Translations/ru.json @@ -1642,6 +1642,16 @@ "description": "Команда для выполнения при смене обоев.", "label": "Обои изменены", "placeholder": "например, notify-send \"Wallpaper\" \"Changed\"" + }, + "screen-lock": { + "description": "Команда для выполнения при блокировке экрана.", + "label": "Экран заблокирован", + "placeholder": "например, notify-send \"Экран\" \"Заблокирован\"" + }, + "screen-unlock": { + "description": "Команда для выполнения при разблокировке экрана.", + "label": "Экран разблокирован", + "placeholder": "например, notify-send \"Экран\" \"Разблокирован\"" } }, "launcher": { diff --git a/Assets/Translations/tr.json b/Assets/Translations/tr.json index 053ddc1fe..b994257bc 100644 --- a/Assets/Translations/tr.json +++ b/Assets/Translations/tr.json @@ -1642,6 +1642,16 @@ "description": "Duvar kâğıdı değiştiğinde çalıştırılacak komut.", "label": "Duvar kâğıdı değişti", "placeholder": "örn., notify-send \"Duvar Kâğıdı\" \"Değişti\"" + }, + "screen-lock": { + "description": "Ekran kilitlendiğinde çalıştırılacak komut.", + "label": "Ekran kilitlendi", + "placeholder": "örn., notify-send \"Ekran\" \"Kilitlendi\"" + }, + "screen-unlock": { + "description": "Ekran kilidi açıldığında çalıştırılacak komut.", + "label": "Ekran kilidi açıldı", + "placeholder": "örn., notify-send \"Ekran\" \"Açıldı\"" } }, "launcher": { diff --git a/Assets/Translations/uk-UA.json b/Assets/Translations/uk-UA.json index a8f4e7645..ccd1b2786 100644 --- a/Assets/Translations/uk-UA.json +++ b/Assets/Translations/uk-UA.json @@ -1642,6 +1642,16 @@ "description": "Команда для виконання при зміні шпалер.", "label": "Шпалери змінено", "placeholder": "напр., notify-send \"Шпалери\" \"Змінено\"" + }, + "screen-lock": { + "description": "Команда для виконання при блокуванні екрана.", + "label": "Екран заблоковано", + "placeholder": "напр., notify-send \"Екран\" \"Заблоковано\"" + }, + "screen-unlock": { + "description": "Команда для виконання при розблокуванні екрана.", + "label": "Екран розблоковано", + "placeholder": "напр., notify-send \"Екран\" \"Розблоковано\"" } }, "launcher": { diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json index 10b480b27..1abacf5eb 100644 --- a/Assets/Translations/zh-CN.json +++ b/Assets/Translations/zh-CN.json @@ -1642,6 +1642,16 @@ "description": "壁纸更改时执行的命令。", "label": "壁纸已更改", "placeholder": "例如:notify-send \"壁纸\" \"已更改\"" + }, + "screen-lock": { + "description": "屏幕锁定时执行的命令。", + "label": "屏幕已锁定", + "placeholder": "例如:notify-send \"屏幕\" \"已锁定\"" + }, + "screen-unlock": { + "description": "屏幕解锁时执行的命令。", + "label": "屏幕已解锁", + "placeholder": "例如:notify-send \"屏幕\" \"已解锁\"" } }, "launcher": { diff --git a/Assets/settings-default.json b/Assets/settings-default.json index 52928de0b..b525cbab8 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -400,7 +400,9 @@ "hooks": { "enabled": false, "wallpaperChange": "", - "darkModeChange": "" + "darkModeChange": "", + "screenLock": "", + "screenUnlock": "" }, "desktopWidgets": { "enabled": false, diff --git a/Commons/Settings.qml b/Commons/Settings.qml index ad2fac0b1..7cc5fd152 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -611,6 +611,8 @@ Singleton { property bool enabled: false property string wallpaperChange: "" property string darkModeChange: "" + property string screenLock: "" + property string screenUnlock: "" } // desktop widgets diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml index dba8ea77d..1c9b8c2f5 100644 --- a/Modules/LockScreen/LockScreen.qml +++ b/Modules/LockScreen/LockScreen.qml @@ -24,6 +24,9 @@ Loader { id: root active: false + // Expose lockContext for hooks + readonly property var lockContext: item ? item.lockContext : null + Component.onCompleted: { // Register with panel service PanelService.lockScreen = this; diff --git a/Modules/Panels/Settings/Tabs/HooksTab.qml b/Modules/Panels/Settings/Tabs/HooksTab.qml index a808227d6..6c661250f 100644 --- a/Modules/Panels/Settings/Tabs/HooksTab.qml +++ b/Modules/Panels/Settings/Tabs/HooksTab.qml @@ -77,6 +77,50 @@ ColumnLayout { Layout.fillWidth: true } + // Screen Lock Hook Section + NInputAction { + id: screenLockHookInput + label: I18n.tr("settings.hooks.screen-lock.label") + description: I18n.tr("settings.hooks.screen-lock.description") + placeholderText: I18n.tr("settings.hooks.screen-lock.placeholder") + text: Settings.data.hooks.screenLock + onEditingFinished: { + Settings.data.hooks.screenLock = screenLockHookInput.text; + } + onActionClicked: { + if (screenLockHookInput.text) { + HooksService.executeLockHook(); + } + } + Layout.fillWidth: true + } + + NDivider { + Layout.fillWidth: true + } + + // Screen Unlock Hook Section + NInputAction { + id: screenUnlockHookInput + label: I18n.tr("settings.hooks.screen-unlock.label") + description: I18n.tr("settings.hooks.screen-unlock.description") + placeholderText: I18n.tr("settings.hooks.screen-unlock.placeholder") + text: Settings.data.hooks.screenUnlock + onEditingFinished: { + Settings.data.hooks.screenUnlock = screenUnlockHookInput.text; + } + onActionClicked: { + if (screenUnlockHookInput.text) { + HooksService.executeUnlockHook(); + } + } + Layout.fillWidth: true + } + + NDivider { + Layout.fillWidth: true + } + // Info section ColumnLayout { spacing: Style.marginM diff --git a/Services/Control/HooksService.qml b/Services/Control/HooksService.qml index 9f2274317..c76ac1d51 100644 --- a/Services/Control/HooksService.qml +++ b/Services/Control/HooksService.qml @@ -23,6 +23,34 @@ Singleton { } } + // 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; + } + } + // Execute wallpaper change hook function executeWallpaperHook(wallpaperPath, screenName) { if (!Settings.data.hooks?.enabled) { @@ -64,8 +92,53 @@ Singleton { } } + // Execute screen lock hook + function executeLockHook() { + if (!Settings.data.hooks?.enabled) { + return; + } + + const script = Settings.data.hooks?.screenLock; + if (!script || script === "") { + return; + } + + try { + Quickshell.execDetached(["sh", "-c", script]); + 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 { + Quickshell.execDetached(["sh", "-c", script]); + Logger.d("HooksService", `Executed screen unlock hook: ${script}`); + } catch (e) { + Logger.e("HooksService", `Failed to execute screen unlock 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; + } + }); } }