diff --git a/electron-builder.yml b/electron-builder.yml index 3270874..c55eb3a 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -5,6 +5,7 @@ directories: files: - '!**/.vscode/*' - '!src/*' + - '!nativeSrc/*' - '!electron.vite.config.{js,ts,mjs,cjs}' - '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}' - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}' diff --git a/nativeSrc/helper.swift b/nativeSrc/helper.swift deleted file mode 100644 index fce2811..0000000 --- a/nativeSrc/helper.swift +++ /dev/null @@ -1,107 +0,0 @@ -import AppKit -import ScreenCaptureKit -import Foundation -import ApplicationServices -import Cocoa -import CoreGraphics - -extension NSBitmapImageRep { - func png() -> Data? { - return representation(using: .png, properties: [:]) - } -} - -extension Data { - var bitmap: NSBitmapImageRep? { - return NSBitmapImageRep(data: self) - } -} - -extension NSImage { - func png() -> Data? { - return tiffRepresentation?.bitmap?.png() - } - - func resized(to size: Int) -> NSImage { - let newSize = CGSize(width: size, height: size) - - let image = NSImage(size: newSize) - image.lockFocus() - NSGraphicsContext.current?.imageInterpolation = .high - - draw( - in: CGRect(origin: .zero, size: newSize), - from: .zero, - operation: .copy, - fraction: 1 - ) - - image.unlockFocus() - return image - } -} - -func getIcon(pid: Int, size: Int) -> Data? { - return NSRunningApplication(processIdentifier: pid_t(pid))?.icon?.resized(to: size).png() -} - -func stringify(data: Data) -> String { - return "data:image/png;base64,\(data.base64EncodedString())" -} - -// ウィンドウ情報の一覧を取得してJSONデータとして返す関数 -func getWindowInfoListData() -> Data? { -// let option: CGWindowListOption = CGWindowListOption(arrayLiteral: .excludeDesktopElements, .optionOnScreenOnly) - let windowsListInfo = CGWindowListCopyWindowInfo([.optionAll], kCGNullWindowID) as! [[String: AnyObject]] - - var windowInfoList: [[String: Any]] = [] - - for windowInfo in windowsListInfo { - var formattedWindowInfo: [String: Any] = [:] - - for (key, value) in windowInfo { - formattedWindowInfo[key] = value - } - - let pid = windowInfo["kCGWindowOwnerPID"] as! Int - if let icon = getIcon(pid: pid, size: 32) { - formattedWindowInfo["appIcon"] = stringify(data: icon) - } - - windowInfoList.append(formattedWindowInfo) - } - - do { - let jsonData = try JSONSerialization.data(withJSONObject: windowInfoList, options: .prettyPrinted) - return jsonData - } catch { - print("Error serializing JSON: \(error)") - return nil - } -} - - - - - - -let arguments = CommandLine.arguments -guard arguments.count > 1 else { - print("引数が必要です") - exit(0) -} -// 第1引数の値によって処理を分岐 -let option = arguments[1] -switch option { -case "grant": - // スクリーンキャプチャのアクセス要求 - CGRequestScreenCaptureAccess() -case "list": - - if let data = getWindowInfoListData() { - let stdOut = FileHandle.standardOutput - stdOut.write(data) - } -default: - print("default") -} diff --git a/nativeSrc/taskbar.helper/main.swift b/nativeSrc/taskbar.helper/main.swift index b1662e0..e70a9b0 100644 --- a/nativeSrc/taskbar.helper/main.swift +++ b/nativeSrc/taskbar.helper/main.swift @@ -86,8 +86,50 @@ func getWindowInfoListData() -> Data? { } +class WindowObserver { + static let shared = WindowObserver() + private init() {} + // ウィンドウの変更を監視 + func observeWindowChanges() { + let notificationCenter = NSWorkspace.shared.notificationCenter + + // アクティブになるイベントの監視 + notificationCenter.addObserver( + self, + selector: #selector(windowDidChange(notification:)), + name: NSWorkspace.didActivateApplicationNotification, + object: nil + ) + + // アプリケーションが起動されたイベントを監視 + notificationCenter.addObserver( + self, + selector: #selector(windowDidChange(notification:)), + name: NSWorkspace.didLaunchApplicationNotification, + object: nil + ) + } + + @objc func windowDidChange(notification: NSNotification) { + // 非同期処理を開始 + DispatchQueue.global(qos: .background).async { + // わずかに遅延させて非同期処理を実行 + // これがないと開いたウィンドウの変更が反映されない + let delayTime = DispatchTime.now() + .milliseconds(500) + + DispatchQueue.global(qos: .background).asyncAfter(deadline: delayTime) { + DispatchQueue.main.async { + if let data = getWindowInfoListData() { + let stdOut = FileHandle.standardOutput + stdOut.write(data) + } + } + } + } + } +} let arguments = CommandLine.arguments @@ -103,11 +145,9 @@ case "grant": CGRequestScreenCaptureAccess() case "list": - if let data = getWindowInfoListData() { - let stdOut = FileHandle.standardOutput - stdOut.write(data) - } + // ウィンドウの変更を監視 + WindowObserver.shared.observeWindowChanges() + RunLoop.main.run() default: print("default") } - diff --git a/resources/TaskbarHelper b/resources/TaskbarHelper index 499d5e7..ea8c80c 100755 Binary files a/resources/TaskbarHelper and b/resources/TaskbarHelper differ diff --git a/src/main/funcs/helper.ts b/src/main/funcs/helper.ts index 3a19e1b..6353e70 100644 --- a/src/main/funcs/helper.ts +++ b/src/main/funcs/helper.ts @@ -14,25 +14,38 @@ if (app.isPackaged) { export const macWindowProcesses: MacWindow[] = [] -export function getAndSubmitProcesses(): void { +export async function getAndSubmitProcesses(): Promise { let rawData = '' try { const taskbarHelper = spawn(binaryPath, ['list']) - taskbarHelper.stdout.on('data', (raw) => { - rawData += raw - }) - taskbarHelper.stderr.on('data', (raw) => { - console.error(raw) - }) - taskbarHelper.on('close', async (code) => { - if ((await code) === 0) { - const jsoned = JSON.parse(Buffer.from(rawData).toString('utf-8')) - applyProcessChange(jsoned) - rawData = '' + + for await (const chunk of taskbarHelper.stdout) { + rawData += chunk.toString() + if (rawData.endsWith(']')) { + try { + const jsoned = JSON.parse(rawData) + await applyProcessChange(jsoned) + rawData = '' + } catch (parseError) { + console.error('Failed to parse JSON:', parseError) + rawData = '' // Reset rawData to avoid accumulating invalid data + } } + } + + taskbarHelper.stderr.on('data', (data) => { + console.error(`TaskbarHelper error: ${data.toString()}`) + }) + + await new Promise((resolve) => { + taskbarHelper.on('close', (code) => { + console.log(`TaskbarHelper process exited with code ${code}`) + resolve() + }) }) - } catch (e) { - console.log(e) + } catch (error) { + console.error('Error in getAndSubmitProcesses:', error); + throw error // Re-throw the error for upper-level error handling } } diff --git a/src/main/main.ts b/src/main/main.ts index 6f08eca..dc0a90c 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -32,10 +32,8 @@ app.whenReady().then(() => { setEventHandlers() }) -// 1秒ごとにプロセスを取得する -setInterval(() => { - getAndSubmitProcesses() -}, 1000) +// プロセスを取得するプロセスを起動 +getAndSubmitProcesses() // Quit when all windows are closed, except on macOS. There, it's common // for applications and their menu bar to stay active until the user quits