Procházet zdrojové kódy

added a button to kill all wallpaper-engine processes

UwU před 2 měsíci
rodič
revize
d5a2c5c3d8

+ 5 - 1
src/main/ipc/lwe.handlers.ts

@@ -1,6 +1,6 @@
 import { ipcMain, type BrowserWindow } from 'electron'
 import { IpcChannels } from '@shared/ipc-channels'
-import { getLweStatus, detectDistro, installLweDeps, installLwe, uninstallLwe, launchLweAsync, stopLwe, isLweRunning } from '../services/lwe.service'
+import { getLweStatus, detectDistro, installLweDeps, installLwe, uninstallLwe, launchLweAsync, stopLwe, isLweRunning, killAllLweProcesses } from '../services/lwe.service'
 import { invalidateEnvCache } from '../services/wallpaper.service'
 
 export function registerLweHandlers(win: BrowserWindow): void {
@@ -38,4 +38,8 @@ export function registerLweHandlers(win: BrowserWindow): void {
     stopLwe()
     return { ok: true }
   })
+
+  ipcMain.handle(IpcChannels.LWE_KILL_ALL, async () => {
+    return await killAllLweProcesses()
+  })
 }

+ 18 - 0
src/main/services/lwe.service.ts

@@ -607,3 +607,21 @@ export function stopLwe(): void {
 export function isLweRunning(): boolean {
   return activeProcess !== null && activeProcess.exitCode === null
 }
+
+/** Force-kill every linux-wallpaperengine process on the system, including ones this app isn't tracking. */
+export async function killAllLweProcesses(): Promise<{ ok: boolean; message: string }> {
+  activeProcess = null
+
+  try {
+    const { stdout } = await execFileAsync('pkill', ['-9', '-f', '-c', LWE_BINARY])
+    const count = parseInt(stdout.trim(), 10) || 0
+    return { ok: true, message: `Killed ${count} process${count === 1 ? '' : 'es'}.` }
+  } catch (err) {
+    const code = (err as { code?: number }).code
+    // pkill exits 1 when nothing matched, that's not a failure here
+    if (code === 1) {
+      return { ok: true, message: 'No running processes found.' }
+    }
+    return { ok: false, message: `Failed to kill processes: ${(err as Error).message}` }
+  }
+}

+ 3 - 1
src/preload/index.ts

@@ -197,7 +197,9 @@ const api = {
     launch: (wallpaperPath: string, options?: { screenRoot?: string; fps?: number }): Promise<{ ok: boolean; running: boolean }> =>
       ipcRenderer.invoke(IpcChannels.LWE_LAUNCH, wallpaperPath, options),
     stop: (): Promise<{ ok: boolean }> =>
-      ipcRenderer.invoke(IpcChannels.LWE_STOP)
+      ipcRenderer.invoke(IpcChannels.LWE_STOP),
+    killAll: (): Promise<{ ok: boolean; message: string }> =>
+      ipcRenderer.invoke(IpcChannels.LWE_KILL_ALL)
   },
 
   backup: {

+ 38 - 1
src/renderer/src/components/settings/SettingsView.tsx

@@ -1,5 +1,5 @@
 import { useState, useEffect } from 'react'
-import { FolderOpen, Save, Upload, Download, CheckCircle, XCircle, Loader2, Package, Trash2, Monitor, RotateCcw, Archive, LayoutGrid, Power } from 'lucide-react'
+import { FolderOpen, Save, Upload, Download, CheckCircle, XCircle, Loader2, Package, Trash2, Monitor, RotateCcw, Archive, LayoutGrid, Power, Skull } from 'lucide-react'
 import type { LweStatus, LweInstallProgress, LinuxDistro } from '../../../../shared/types'
 
 const DISTRO_LABELS: Record<LinuxDistro, string> = {
@@ -30,6 +30,8 @@ export default function SettingsView() {
   const [depsInstalling, setDepsInstalling] = useState(false)
   const [uninstalling, setUninstalling] = useState(false)
   const [uninstallMsg, setUninstallMsg] = useState<string | null>(null)
+  const [killingLwe, setKillingLwe] = useState(false)
+  const [killMsg, setKillMsg] = useState<string | null>(null)
 
   // Desktop icons overlay
   const [desktopIconsEnabled, setDesktopIconsEnabled] = useState(false)
@@ -162,6 +164,19 @@ export default function SettingsView() {
     }
   }
 
+  async function handleKillAllLwe() {
+    setKillingLwe(true)
+    setKillMsg(null)
+    try {
+      const result = await window.electronAPI.lwe.killAll()
+      setKillMsg(result.message)
+    } catch (err) {
+      setKillMsg(`Failed: ${(err as Error).message}`)
+    } finally {
+      setKillingLwe(false)
+    }
+  }
+
   async function handleSaveDefaultFps() {
     const parsed = defaultFps.trim() === '' ? null : parseInt(defaultFps, 10)
     if (parsed !== null && (isNaN(parsed) || parsed < 1)) return
@@ -563,6 +578,28 @@ export default function SettingsView() {
             </div>
           )}
 
+          {/* Kill stray processes */}
+          <div className="mt-4">
+            <button
+              onClick={handleKillAllLwe}
+              disabled={killingLwe}
+              className="flex items-center gap-2 rounded-lg bg-red-600/20 px-4 py-2 text-sm text-red-400 hover:bg-red-600/30 disabled:opacity-50"
+            >
+              {killingLwe ? (
+                <Loader2 size={14} className="animate-spin" />
+              ) : (
+                <Skull size={14} />
+              )}
+              {killingLwe ? 'Killing...' : 'Kill all linux-wallpaperengine processes'}
+            </button>
+            <p className="mt-1 text-xs text-gray-600">
+              Force-kills every running instance, including ones not launched by WE Manager.
+            </p>
+            {killMsg && (
+              <p className="mt-2 text-xs text-gray-400">{killMsg}</p>
+            )}
+          </div>
+
           {/* Install progress */}
           {lweProgress && (
             <div className="mt-3 space-y-2">

+ 1 - 0
src/shared/ipc-channels.ts

@@ -98,6 +98,7 @@ export const IpcChannels = {
   LWE_UNINSTALL: 'lwe:uninstall',
   LWE_LAUNCH: 'lwe:launch',
   LWE_STOP: 'lwe:stop',
+  LWE_KILL_ALL: 'lwe:kill-all',
 
   // Desktop icons overlay
   DESKTOP_ICONS_SET_ENABLED: 'desktop-icons:set-enabled',