diff --git a/packages/client-api/src/desktop/monitors.ts b/packages/client-api/src/desktop/monitors.ts index 0c9cd27a..4bdb8dcf 100644 --- a/packages/client-api/src/desktop/monitors.ts +++ b/packages/client-api/src/desktop/monitors.ts @@ -3,98 +3,26 @@ import { availableMonitors as getAvailableMonitors, currentMonitor as getCurrentMonitor, primaryMonitor as getPrimaryMonitor, + getCurrent as getCurrentWindow, } from '@tauri-apps/api/window'; import { createStore } from 'solid-js/store'; -import { type Owner, createEffect, runWithOwner } from 'solid-js'; import type { MonitorInfo } from './shared'; -let fetchMonitorsPromise: ReturnType | null = null; +let createCachePromise: Promise | null = null; -/** - * Store of available monitors. Lazily initialize as values are fetched. - */ -const [monitorCache, setMonitorCache] = createStore({ - current: { - value: null as MonitorInfo | null, - isFetching: false, - isInitialized: false, - }, - primary: { - value: null as MonitorInfo | null, - isFetching: false, - isInitialized: false, - }, - secondary: { - value: [] as MonitorInfo[], - isFetching: false, - isInitialized: false, - }, - all: { - value: [] as MonitorInfo[], - isFetching: false, - isInitialized: false, - }, -}); - -export async function getMonitors() { - return fetchMonitorsPromise ?? (fetchMonitorsPromise = fetchMonitors()); +interface MonitorCache { + currentMonitor: MonitorInfo | null; + primaryMonitor: MonitorInfo | null; + secondaryMonitors: MonitorInfo[]; + allMonitors: MonitorInfo[]; } -// export async function _getAllMonitors(owner: Owner) { -// return createSharedCache('all-monitors', async () => { -// getAvailableMonitors(), -// }); -// } - -// export async function __getPrimaryMonitor(owner: Owner) { -// return createSharedCache('primary-monitor', async () => { -// getPrimaryMonitor(), -// }); -// } - -// export async function __getCurrentMonitor(owner: Owner) { -// const monitorMap = await createSharedCache('monitor-map', async () => -// getPrimaryMonitor(), -// ); -// } - -// export async function getMonitorCache(owner: Owner) { -// const monitorCache = await createSharedCache('monitors', async () => -// getMonitorCache(), -// ); -// } - -export async function _getPrimaryMonitor(owner: Owner) { - if (monitorCache.primary.isInitialized) { - return monitorCache.primary.value; - } - - if (monitorCache.primary.isFetching) { - runWithOwner(owner, () => { - createEffect(() => { - if (!monitorCache.primary.isFetching) { - return Promise.resolve(monitorCache.primary.value); - } - }); - }); - } - - setMonitorCache('primary', 'isFetching', true); - - const primaryMonitor = await getPrimaryMonitor(); - const value = primaryMonitor ? toMonitorInfo(primaryMonitor) : null; - - setMonitorCache('primary', { - value, - isFetching: false, - isInitialized: true, - }); - - return value; +export async function getMonitors() { + return createCachePromise ?? (createCachePromise = createMonitorCache()); } -async function fetchMonitors() { +async function createMonitorCache() { const [currentMonitor, primaryMonitor, allMonitors] = await Promise.all([ getCurrentMonitor(), getPrimaryMonitor(), @@ -109,12 +37,28 @@ async function fetchMonitors() { // return value, and refresh it in an effect when displays are changed. // Ref https://github.com/tauri-apps/tauri/issues/8405 - return { + const [monitorCache, setMonitorCache] = createStore({ currentMonitor: currentMonitor ? toMonitorInfo(currentMonitor) : null, primaryMonitor: primaryMonitor ? toMonitorInfo(primaryMonitor) : null, secondaryMonitors: secondaryMonitors.map(toMonitorInfo), allMonitors: allMonitors.map(toMonitorInfo), - }; + }); + + getCurrentWindow().onResized(() => updateCurrentMonitor()); + getCurrentWindow().onMoved(() => updateCurrentMonitor()); + + // Update the current monitor when the window is moved or resized. + async function updateCurrentMonitor() { + const currentMonitor = await getCurrentMonitor(); + + setMonitorCache({ + currentMonitor: currentMonitor + ? toMonitorInfo(currentMonitor) + : null, + }); + } + + return monitorCache; } function isMatch(monitorA: Monitor, monitorB: Monitor) { diff --git a/packages/client-api/src/providers/glazewm/create-glazewm-provider.ts b/packages/client-api/src/providers/glazewm/create-glazewm-provider.ts index af61de73..2c4d62bc 100644 --- a/packages/client-api/src/providers/glazewm/create-glazewm-provider.ts +++ b/packages/client-api/src/providers/glazewm/create-glazewm-provider.ts @@ -1,4 +1,4 @@ -import type { Owner } from 'solid-js'; +import { createEffect, on, runWithOwner, type Owner } from 'solid-js'; import { createStore } from 'solid-js/store'; import { GwmClient, GwmEventType, type Workspace } from 'glazewm'; @@ -8,9 +8,9 @@ import { getCoordinateDistance } from '~/utils'; export async function createGlazewmProvider( _: GlazewmProviderConfig, - __: Owner, + owner: Owner, ) { - const { currentMonitor } = await getMonitors(); + const monitors = await getMonitors(); const client = new GwmClient(); const [glazewmVariables, setGlazewmVariables] = createStore({ @@ -29,26 +29,36 @@ export async function createGlazewmProvider( await client.subscribeMany( [ - GwmEventType.WORKSPACE_ACTIVATED, + GwmEventType.WORKSPACE_ACTIVATED, GwmEventType.WORKSPACE_DEACTIVATED, - GwmEventType.FOCUS_CHANGED + GwmEventType.FOCUS_CHANGED, ], refetch, ); + runWithOwner(owner, () => { + createEffect(on(() => monitors.currentMonitor, refetch)); + }); + async function refetch() { - const monitors = await client.getMonitors(); - const currentPosition = { x: currentMonitor!.x, y: currentMonitor!.y }; + const currentPosition = { + x: monitors.currentMonitor!.x, + y: monitors.currentMonitor!.y, + }; // Get GlazeWM monitor that corresponds to the bar's monitor. - const monitor = monitors.reduce((a, b) => + const glazewmMonitor = (await client.getMonitors()).reduce((a, b) => getCoordinateDistance(currentPosition, a) < getCoordinateDistance(currentPosition, b) ? a : b, ); - setGlazewmVariables({ workspacesOnMonitor: monitor.children.sort((a, b) => Number(a.name) - Number(b.name)) }); + setGlazewmVariables({ + workspacesOnMonitor: glazewmMonitor.children.sort( + (a, b) => Number(a.name) - Number(b.name), + ), + }); } return { diff --git a/packages/client-api/src/providers/komorebi/create-komorebi-provider.ts b/packages/client-api/src/providers/komorebi/create-komorebi-provider.ts index 9f5ffcf9..4d4c8bbf 100644 --- a/packages/client-api/src/providers/komorebi/create-komorebi-provider.ts +++ b/packages/client-api/src/providers/komorebi/create-komorebi-provider.ts @@ -1,4 +1,4 @@ -import { createEffect, type Owner } from 'solid-js'; +import { createEffect, runWithOwner, type Owner } from 'solid-js'; import { createStore } from 'solid-js/store'; import type { KomorebiProviderConfig } from '~/user-config'; @@ -110,7 +110,7 @@ export async function createKomorebiProvider( config: KomorebiProviderConfig, owner: Owner, ): Promise { - const { currentMonitor } = await getMonitors(); + const monitors = await getMonitors(); const providerListener = await createProviderListener< KomorebiProviderConfig, @@ -121,11 +121,17 @@ export async function createKomorebiProvider( await getVariables(), ); - createEffect(async () => setKomorebiVariables(await getVariables())); + runWithOwner(owner, () => { + createEffect(async () => setKomorebiVariables(await getVariables())); + }); async function getVariables() { const state = providerListener(); - const currentPosition = { x: currentMonitor!.x, y: currentMonitor!.y }; + + const currentPosition = { + x: monitors.currentMonitor!.x, + y: monitors.currentMonitor!.y, + }; // Get Komorebi monitor that corresponds to the window's monitor. const currentKomorebiMonitor = state.allMonitors.reduce((a, b) => @@ -141,25 +147,29 @@ export async function createKomorebiProvider( : b, ); - const displayedWorkspace = + const displayedKomorebiWorkspace = currentKomorebiMonitor.workspaces[ currentKomorebiMonitor.focusedWorkspaceIndex ]!; - const allWorkspaces = state.allMonitors.flatMap( + const allKomorebiWorkspaces = state.allMonitors.flatMap( monitor => monitor.workspaces, ); - const focusedMonitor = state.allMonitors[state.focusedMonitorIndex]!; - const focusedWorkspace = - focusedMonitor.workspaces[focusedMonitor.focusedWorkspaceIndex]!; + const focusedKomorebiMonitor = + state.allMonitors[state.focusedMonitorIndex]!; + + const focusedKomorebiWorkspace = + focusedKomorebiMonitor.workspaces[ + focusedKomorebiMonitor.focusedWorkspaceIndex + ]!; return { - displayedWorkspace, - focusedWorkspace, + displayedWorkspace: displayedKomorebiWorkspace, + focusedWorkspace: focusedKomorebiWorkspace, currentWorkspaces: currentKomorebiMonitor.workspaces, - allWorkspaces, - focusedMonitor, + allWorkspaces: allKomorebiWorkspaces, + focusedMonitor: focusedKomorebiMonitor, currentMonitor: currentKomorebiMonitor, allMonitors: state.allMonitors, };