@owdproject/nuxt 0.0.0-stage → 4.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +77 -2
  3. package/dist/kit/authoring.d.ts +88 -0
  4. package/dist/kit/authoring.js +276 -0
  5. package/dist/kit/defineDesktopApp.d.ts +1 -0
  6. package/dist/kit/defineDesktopApp.js +1 -0
  7. package/dist/kit/defineDesktopPlugin.d.ts +1 -0
  8. package/dist/kit/defineDesktopPlugin.js +1 -0
  9. package/dist/module.d.mts +245 -0
  10. package/dist/module.json +12 -0
  11. package/dist/module.mjs +681 -0
  12. package/dist/runtime/components/Application/DesktopCoreApplicationRender.d.vue.ts +6 -0
  13. package/dist/runtime/components/Application/DesktopCoreApplicationRender.vue +18 -0
  14. package/dist/runtime/components/Application/DesktopCoreApplicationRender.vue.d.ts +6 -0
  15. package/dist/runtime/components/Application/DesktopCoreApplicationWindowsRender.d.vue.ts +9 -0
  16. package/dist/runtime/components/Application/DesktopCoreApplicationWindowsRender.vue +31 -0
  17. package/dist/runtime/components/Application/DesktopCoreApplicationWindowsRender.vue.d.ts +9 -0
  18. package/dist/runtime/components/DesktopCore.d.vue.ts +19 -0
  19. package/dist/runtime/components/DesktopCore.vue +37 -0
  20. package/dist/runtime/components/DesktopCore.vue.d.ts +19 -0
  21. package/dist/runtime/components/background/DesktopCoreBackground.d.vue.ts +13 -0
  22. package/dist/runtime/components/background/DesktopCoreBackground.vue +16 -0
  23. package/dist/runtime/components/background/DesktopCoreBackground.vue.d.ts +13 -0
  24. package/dist/runtime/components/time/DesktopCoreTime.d.vue.ts +3 -0
  25. package/dist/runtime/components/time/DesktopCoreTime.vue +44 -0
  26. package/dist/runtime/components/time/DesktopCoreTime.vue.d.ts +3 -0
  27. package/dist/runtime/components/window/DesktopCoreWindow.d.vue.ts +49 -0
  28. package/dist/runtime/components/window/DesktopCoreWindow.vue +438 -0
  29. package/dist/runtime/components/window/DesktopCoreWindow.vue.d.ts +49 -0
  30. package/dist/runtime/components/window/DesktopCoreWindowContent.d.vue.ts +13 -0
  31. package/dist/runtime/components/window/DesktopCoreWindowContent.vue +34 -0
  32. package/dist/runtime/components/window/DesktopCoreWindowContent.vue.d.ts +13 -0
  33. package/dist/runtime/components/window/DesktopCoreWindowNav.d.vue.ts +13 -0
  34. package/dist/runtime/components/window/DesktopCoreWindowNav.vue +54 -0
  35. package/dist/runtime/components/window/DesktopCoreWindowNav.vue.d.ts +13 -0
  36. package/dist/runtime/components/window/DesktopCoreWindowSnapHintsBase.d.vue.ts +19 -0
  37. package/dist/runtime/components/window/DesktopCoreWindowSnapHintsBase.vue +46 -0
  38. package/dist/runtime/components/window/DesktopCoreWindowSnapHintsBase.vue.d.ts +19 -0
  39. package/dist/runtime/components/workspace/DesktopCoreWorkspaceEdgeHintsBase.d.vue.ts +24 -0
  40. package/dist/runtime/components/workspace/DesktopCoreWorkspaceEdgeHintsBase.vue +50 -0
  41. package/dist/runtime/components/workspace/DesktopCoreWorkspaceEdgeHintsBase.vue.d.ts +24 -0
  42. package/dist/runtime/composables/application/state.d.ts +1 -0
  43. package/dist/runtime/composables/application/state.js +2 -0
  44. package/dist/runtime/composables/application/useDesktopApplicationDefine.d.ts +4 -0
  45. package/dist/runtime/composables/application/useDesktopApplicationDefine.js +36 -0
  46. package/dist/runtime/composables/application/useDesktopApplicationExec.d.ts +3 -0
  47. package/dist/runtime/composables/application/useDesktopApplicationExec.js +26 -0
  48. package/dist/runtime/composables/application/useDesktopApplicationProcess.d.ts +24 -0
  49. package/dist/runtime/composables/application/useDesktopApplicationProcess.js +140 -0
  50. package/dist/runtime/composables/application/useDesktopApplicationRegistry.d.ts +11 -0
  51. package/dist/runtime/composables/application/useDesktopApplicationRegistry.js +60 -0
  52. package/dist/runtime/composables/useApplicationEntries.d.ts +5 -0
  53. package/dist/runtime/composables/useApplicationEntries.js +10 -0
  54. package/dist/runtime/composables/useApplicationManager.d.ts +16 -0
  55. package/dist/runtime/composables/useApplicationManager.js +30 -0
  56. package/dist/runtime/composables/useBlockNonInputContextMenu.d.ts +5 -0
  57. package/dist/runtime/composables/useBlockNonInputContextMenu.js +19 -0
  58. package/dist/runtime/composables/useDesktop.d.ts +210 -0
  59. package/dist/runtime/composables/useDesktop.js +52 -0
  60. package/dist/runtime/composables/useDesktopApplication.d.ts +34 -0
  61. package/dist/runtime/composables/useDesktopApplication.js +17 -0
  62. package/dist/runtime/composables/useDesktopCommands.d.ts +12 -0
  63. package/dist/runtime/composables/useDesktopCommands.js +348 -0
  64. package/dist/runtime/composables/useDesktopConfig.d.ts +3 -0
  65. package/dist/runtime/composables/useDesktopConfig.js +10 -0
  66. package/dist/runtime/composables/useDesktopDefaultApps.d.ts +15 -0
  67. package/dist/runtime/composables/useDesktopDefaultApps.js +21 -0
  68. package/dist/runtime/composables/useDesktopDialogs.d.ts +5 -0
  69. package/dist/runtime/composables/useDesktopDialogs.js +8 -0
  70. package/dist/runtime/composables/useDesktopDrag.d.ts +1 -0
  71. package/dist/runtime/composables/useDesktopDrag.js +1 -0
  72. package/dist/runtime/composables/useDesktopHooks.d.ts +15 -0
  73. package/dist/runtime/composables/useDesktopHooks.js +12 -0
  74. package/dist/runtime/composables/useDesktopIPC.d.ts +35 -0
  75. package/dist/runtime/composables/useDesktopIPC.js +72 -0
  76. package/dist/runtime/composables/useDesktopIdentity.d.ts +22 -0
  77. package/dist/runtime/composables/useDesktopIdentity.js +65 -0
  78. package/dist/runtime/composables/useDesktopManifest.d.ts +6 -0
  79. package/dist/runtime/composables/useDesktopManifest.js +17 -0
  80. package/dist/runtime/composables/useDesktopNotification.d.ts +13 -0
  81. package/dist/runtime/composables/useDesktopNotification.js +13 -0
  82. package/dist/runtime/composables/useDesktopResize.d.ts +1 -0
  83. package/dist/runtime/composables/useDesktopResize.js +1 -0
  84. package/dist/runtime/composables/useDesktopSession.d.ts +4 -0
  85. package/dist/runtime/composables/useDesktopSession.js +17 -0
  86. package/dist/runtime/composables/useDesktopShellIdentity.d.ts +1 -0
  87. package/dist/runtime/composables/useDesktopShellIdentity.js +3 -0
  88. package/dist/runtime/composables/useDesktopShellOptions.d.ts +5 -0
  89. package/dist/runtime/composables/useDesktopShellOptions.js +18 -0
  90. package/dist/runtime/composables/useDesktopTray.d.ts +5 -0
  91. package/dist/runtime/composables/useDesktopTray.js +10 -0
  92. package/dist/runtime/composables/useDesktopVolume.d.ts +4 -0
  93. package/dist/runtime/composables/useDesktopVolume.js +9 -0
  94. package/dist/runtime/composables/useDesktopWorkArea.d.ts +1 -0
  95. package/dist/runtime/composables/useDesktopWorkArea.js +3 -0
  96. package/dist/runtime/composables/useDesktopWorkarea.d.ts +12 -0
  97. package/dist/runtime/composables/useDesktopWorkarea.js +72 -0
  98. package/dist/runtime/composables/useTerminalManager.d.ts +15 -0
  99. package/dist/runtime/composables/useTerminalManager.js +9 -0
  100. package/dist/runtime/composables/useToggleWindowMaximize.d.ts +1 -0
  101. package/dist/runtime/composables/useToggleWindowMaximize.js +12 -0
  102. package/dist/runtime/composables/useWindowDragHandlers.d.ts +7 -0
  103. package/dist/runtime/composables/useWindowDragHandlers.js +7 -0
  104. package/dist/runtime/composables/window/useDesktopWindow.d.ts +14 -0
  105. package/dist/runtime/composables/window/useDesktopWindow.js +192 -0
  106. package/dist/runtime/composables/window/useDesktopWindowSnapDrop.d.ts +13 -0
  107. package/dist/runtime/composables/window/useDesktopWindowSnapDrop.js +78 -0
  108. package/dist/runtime/composables/workspace/useDesktopWorkspaceEdgeDrop.d.ts +25 -0
  109. package/dist/runtime/composables/workspace/useDesktopWorkspaceEdgeDrop.js +119 -0
  110. package/dist/runtime/composables/workspace/useDesktopWorkspaceManager.d.ts +8 -0
  111. package/dist/runtime/composables/workspace/useDesktopWorkspaceManager.js +46 -0
  112. package/dist/runtime/composables/workspace/useDesktopWorkspaceOverviewCapture.d.ts +20 -0
  113. package/dist/runtime/composables/workspace/useDesktopWorkspaceOverviewCapture.js +60 -0
  114. package/dist/runtime/composables/workspace/useDesktopWorkspaceOverviewLiveScale.d.ts +31 -0
  115. package/dist/runtime/composables/workspace/useDesktopWorkspaceOverviewLiveScale.js +92 -0
  116. package/dist/runtime/constants/desktopShellKeys.d.ts +5 -0
  117. package/dist/runtime/constants/desktopShellKeys.js +2 -0
  118. package/dist/runtime/constants/shellLayout.d.ts +4 -0
  119. package/dist/runtime/constants/shellLayout.js +2 -0
  120. package/dist/runtime/dialogs/desktopDialogProvider.d.ts +6 -0
  121. package/dist/runtime/dialogs/desktopDialogProvider.js +12 -0
  122. package/dist/runtime/internal/controllers/ApplicationController.d.ts +44 -0
  123. package/dist/runtime/internal/controllers/ApplicationController.js +470 -0
  124. package/dist/runtime/internal/controllers/WindowController.d.ts +83 -0
  125. package/dist/runtime/internal/controllers/WindowController.js +435 -0
  126. package/dist/runtime/plugins/01.desktop-shell-init.client.d.ts +2 -0
  127. package/dist/runtime/plugins/01.desktop-shell-init.client.js +18 -0
  128. package/dist/runtime/plugins/02.desktop-register-desktop-apps.client.d.ts +2 -0
  129. package/dist/runtime/plugins/02.desktop-register-desktop-apps.client.js +7 -0
  130. package/dist/runtime/stores/storeApplicationMeta.d.ts +2 -0
  131. package/dist/runtime/stores/storeApplicationMeta.js +30 -0
  132. package/dist/runtime/stores/storeApplicationWindows.d.ts +2 -0
  133. package/dist/runtime/stores/storeApplicationWindows.js +43 -0
  134. package/dist/runtime/stores/storeDesktop.d.ts +17 -0
  135. package/dist/runtime/stores/storeDesktop.js +29 -0
  136. package/dist/runtime/stores/storeDesktopDefaultApps.d.ts +8 -0
  137. package/dist/runtime/stores/storeDesktopDefaultApps.js +21 -0
  138. package/dist/runtime/stores/storeDesktopTray.d.ts +6 -0
  139. package/dist/runtime/stores/storeDesktopTray.js +21 -0
  140. package/dist/runtime/stores/storeDesktopVolume.d.ts +4 -0
  141. package/dist/runtime/stores/storeDesktopVolume.js +12 -0
  142. package/dist/runtime/stores/storeDesktopWorkspace.d.ts +26 -0
  143. package/dist/runtime/stores/storeDesktopWorkspace.js +103 -0
  144. package/dist/runtime/stores/storeNotification.d.ts +27 -0
  145. package/dist/runtime/stores/storeNotification.js +62 -0
  146. package/dist/runtime/types/index.d.ts +1 -0
  147. package/dist/runtime/types/index.js +1 -0
  148. package/dist/runtime/utils/defineDesktopApp.d.ts +2 -0
  149. package/dist/runtime/utils/defineDesktopApp.js +5 -0
  150. package/dist/runtime/utils/defineDesktopPlugin.d.ts +19 -0
  151. package/dist/runtime/utils/defineDesktopPlugin.js +29 -0
  152. package/dist/runtime/utils/utilApp.d.ts +2 -0
  153. package/dist/runtime/utils/utilApp.js +9 -0
  154. package/dist/runtime/utils/utilCaptureElementToCanvas.d.ts +1 -0
  155. package/dist/runtime/utils/utilCaptureElementToCanvas.js +21 -0
  156. package/dist/runtime/utils/utilDebug.d.ts +4 -0
  157. package/dist/runtime/utils/utilDebug.js +24 -0
  158. package/dist/runtime/utils/utilDetectSnapZone.d.ts +1 -0
  159. package/dist/runtime/utils/utilDetectSnapZone.js +5 -0
  160. package/dist/runtime/utils/utilWindowControllerAdapter.d.ts +2 -0
  161. package/dist/runtime/utils/utilWindowControllerAdapter.js +151 -0
  162. package/dist/runtime/utils/utilWindowLayout.d.ts +4 -0
  163. package/dist/runtime/utils/utilWindowLayout.js +34 -0
  164. package/dist/runtime/utils/utilWorkspaceWindows.d.ts +2 -0
  165. package/dist/runtime/utils/utilWorkspaceWindows.js +12 -0
  166. package/dist/types/index.d.ts +164 -0
  167. package/dist/types/index.js +1 -0
  168. package/dist/types.d.mts +2 -0
  169. package/package.json +151 -4
@@ -0,0 +1,92 @@
1
+ import {
2
+ nextTick,
3
+ onScopeDispose,
4
+ readonly,
5
+ shallowRef,
6
+ watch
7
+ } from "vue";
8
+ import { useDesktopWorkspaceStore } from "../../stores/storeDesktopWorkspace.js";
9
+ export function computeScaleToFit(panelWidth, panelHeight, stageWidth, stageHeight, options) {
10
+ if (panelWidth <= 0 || panelHeight <= 0 || stageWidth <= 0 || stageHeight <= 0) {
11
+ return 1;
12
+ }
13
+ const scale = Math.min(panelWidth / stageWidth, panelHeight / stageHeight);
14
+ const maxScale = options?.maxScale ?? 1;
15
+ return Math.min(scale, maxScale);
16
+ }
17
+ export function useDesktopWorkspaceOverviewLiveScale(shellStageRef) {
18
+ const desktopWorkspaceStore = useDesktopWorkspaceStore();
19
+ const stageSize = shallowRef({ width: 0, height: 0 });
20
+ let resizeObserver = null;
21
+ function readStageSize() {
22
+ const el = shellStageRef.value;
23
+ if (!el) {
24
+ stageSize.value = { width: 0, height: 0 };
25
+ return;
26
+ }
27
+ stageSize.value = {
28
+ width: el.clientWidth,
29
+ height: el.clientHeight
30
+ };
31
+ }
32
+ function stopObserving() {
33
+ resizeObserver?.disconnect();
34
+ resizeObserver = null;
35
+ }
36
+ function startObserving() {
37
+ stopObserving();
38
+ const el = shellStageRef.value;
39
+ if (!el || typeof ResizeObserver === "undefined") return;
40
+ readStageSize();
41
+ resizeObserver = new ResizeObserver(() => readStageSize());
42
+ resizeObserver.observe(el);
43
+ }
44
+ watch(
45
+ () => desktopWorkspaceStore.overview,
46
+ (open) => {
47
+ if (open) {
48
+ void nextTick(() => startObserving());
49
+ } else {
50
+ stopObserving();
51
+ stageSize.value = { width: 0, height: 0 };
52
+ }
53
+ }
54
+ );
55
+ watch(shellStageRef, (el) => {
56
+ if (desktopWorkspaceStore.overview && el) {
57
+ void nextTick(() => startObserving());
58
+ }
59
+ });
60
+ onScopeDispose(stopObserving);
61
+ function scaleToFit(panelEl, options) {
62
+ if (!panelEl) return 1;
63
+ const { width: stageWidth, height: stageHeight } = stageSize.value;
64
+ if (stageWidth <= 0 || stageHeight <= 0) return 1;
65
+ return computeScaleToFit(
66
+ panelEl.clientWidth,
67
+ panelEl.clientHeight,
68
+ stageWidth,
69
+ stageHeight,
70
+ options
71
+ );
72
+ }
73
+ function innerOverviewStyle(panelEl, options) {
74
+ if (!desktopWorkspaceStore.overview) return void 0;
75
+ const { width: stageWidth, height: stageHeight } = stageSize.value;
76
+ if (stageWidth <= 0 || stageHeight <= 0) return void 0;
77
+ const scale = scaleToFit(panelEl, options);
78
+ const transformOrigin = options?.transformOrigin ?? "top left";
79
+ return {
80
+ width: `${stageWidth}px`,
81
+ height: `${stageHeight}px`,
82
+ transform: `scale(${scale})`,
83
+ transformOrigin
84
+ };
85
+ }
86
+ return {
87
+ stageSize: readonly(stageSize),
88
+ scaleToFit,
89
+ innerOverviewStyle,
90
+ refreshStageSize: readStageSize
91
+ };
92
+ }
@@ -0,0 +1,5 @@
1
+ import type { InjectionKey } from 'vue';
2
+ import type { DesktopDialogProvider } from '../dialogs/desktopDialogProvider.js';
3
+ export type DesktopToggleWindowMaximizeFn = (win: IWindowController | undefined) => boolean;
4
+ export declare const DESKTOP_DIALOG_PROVIDER_KEY: InjectionKey<DesktopDialogProvider>;
5
+ export declare const DESKTOP_TOGGLE_WINDOW_MAXIMIZE_KEY: InjectionKey<DesktopToggleWindowMaximizeFn>;
@@ -0,0 +1,2 @@
1
+ export const DESKTOP_DIALOG_PROVIDER_KEY = Symbol("desktop-dialog-provider");
2
+ export const DESKTOP_TOGGLE_WINDOW_MAXIMIZE_KEY = Symbol("desktop-toggle-window-maximize");
@@ -0,0 +1,4 @@
1
+ /** Viewport band (px) where a window drag targets the adjacent workspace. */
2
+ export declare const WORKSPACE_EDGE_DROP_PX = 72;
3
+ /** Viewport band (px) where a window drag targets a snap zone. */
4
+ export declare const WINDOW_SNAP_EDGE_PX = 14;
@@ -0,0 +1,2 @@
1
+ export const WORKSPACE_EDGE_DROP_PX = 72;
2
+ export const WINDOW_SNAP_EDGE_PX = 14;
@@ -0,0 +1,6 @@
1
+ export interface DesktopDialogProvider {
2
+ alert(message: string, title?: string): Promise<void>;
3
+ confirm(message: string, title?: string): Promise<boolean>;
4
+ prompt(message: string, defaultValue?: string, title?: string): Promise<string | null>;
5
+ }
6
+ export declare function createBrowserFallbackDialogProvider(): DesktopDialogProvider;
@@ -0,0 +1,12 @@
1
+ export function createBrowserFallbackDialogProvider() {
2
+ return {
3
+ async alert(_message) {
4
+ },
5
+ async confirm(_message) {
6
+ return true;
7
+ },
8
+ async prompt(_message, defaultValue = "") {
9
+ return defaultValue;
10
+ }
11
+ };
12
+ }
@@ -0,0 +1,44 @@
1
+ import { type ApplicationConfig, type CommandOutput, type WindowStoredState } from '@owdproject/core';
2
+ import type { IApplicationController, IWindowController } from '../../../types/index.js';
3
+ import { useApplicationWindowsStore } from '../../stores/storeApplicationWindows.js';
4
+ export declare class ApplicationController implements IApplicationController {
5
+ readonly id: string;
6
+ readonly config: ApplicationConfig;
7
+ readonly windows: import("vue").ShallowReactive<Map<string, IWindowController>>;
8
+ readonly openWindowCount: import("vue").ShallowRef<number, number>;
9
+ storeWindows: ReturnType<typeof useApplicationWindowsStore> | undefined;
10
+ storeMeta: any;
11
+ private readonly _pid;
12
+ private readonly _startedAt;
13
+ private readonly _stateValue;
14
+ private readonly _isRunning;
15
+ private readonly _isSuspended;
16
+ private appActor;
17
+ constructor(id: string, config: ApplicationConfig);
18
+ get windowsOpened(): Map<string, IWindowController>;
19
+ getFirstWindowByModel(model: string): IWindowController | undefined;
20
+ get pid(): number | null;
21
+ get startedAt(): number | null;
22
+ get stateValue(): string;
23
+ get isRunning(): boolean;
24
+ get isSuspended(): boolean;
25
+ get isInitializing(): boolean;
26
+ get isReady(): boolean;
27
+ initApplication(): Promise<void>;
28
+ /**
29
+ * Reopen the windows persisted in this application's window store. Returns
30
+ * `true` when at least one window was restored. No-op without a persistence
31
+ * adapter (the window store is then always empty at boot).
32
+ */
33
+ restoreApplication(): Promise<boolean>;
34
+ private restoreWindows;
35
+ focusWindow(targetWin: IWindowController): void;
36
+ openWindow(model: string, storedState?: WindowStoredState, meta?: Record<string, any>): IWindowController | undefined;
37
+ closeWindow(windowId: string): void;
38
+ closeAllWindows(): void;
39
+ setRunning(value: boolean): void;
40
+ suspend(): void;
41
+ resume(): void;
42
+ sendSignal(signal?: 'SIGTERM' | 'SIGKILL' | 'SIGSTOP' | 'SIGCONT'): void;
43
+ execCommand(command: string): Promise<CommandOutput | void>;
44
+ }
@@ -0,0 +1,470 @@
1
+ import { markRaw, reactive, shallowRef, shallowReactive } from "vue";
2
+ import { createActor } from "xstate";
3
+ import { nanoid } from "nanoid";
4
+ import {
5
+ applicationMachine,
6
+ computeSnapRect
7
+ } from "@owdproject/core";
8
+ import { WindowController } from "./WindowController.js";
9
+ import { apps } from "../../composables/application/state.js";
10
+ import { useDesktopCommands } from "../../composables/useDesktopCommands.js";
11
+ import { useDesktopDefaultApps } from "../../composables/useDesktopDefaultApps.js";
12
+ import { useDesktopHooks } from "../../composables/useDesktopHooks.js";
13
+ import { useDesktopIPC } from "../../composables/useDesktopIPC.js";
14
+ import { useDesktopStore } from "../../stores/storeDesktop.js";
15
+ import { useDesktopWorkspaceStore } from "../../stores/storeDesktopWorkspace.js";
16
+ import { useApplicationWindowsStore } from "../../stores/storeApplicationWindows.js";
17
+ import { useApplicationMetaStore } from "../../stores/storeApplicationMeta.js";
18
+ let globalPidCounter = 1e3;
19
+ function formatAppSnapshotValue(value) {
20
+ if (typeof value === "string") return value;
21
+ if (value && typeof value === "object") {
22
+ const entries = Object.entries(value);
23
+ if (entries.length > 0) {
24
+ const [k, v] = entries[0];
25
+ return `${k}.${formatAppSnapshotValue(v)}`;
26
+ }
27
+ }
28
+ return "idle";
29
+ }
30
+ export class ApplicationController {
31
+ id;
32
+ config;
33
+ windows = shallowReactive(/* @__PURE__ */ new Map());
34
+ openWindowCount = shallowRef(0);
35
+ storeWindows;
36
+ storeMeta;
37
+ _pid = shallowRef(null);
38
+ _startedAt = shallowRef(null);
39
+ _stateValue = shallowRef("idle");
40
+ _isRunning = shallowRef(false);
41
+ _isSuspended = shallowRef(false);
42
+ appActor;
43
+ constructor(id, config) {
44
+ this.id = id;
45
+ this.config = config;
46
+ this.appActor = createActor(applicationMachine, {
47
+ input: {
48
+ id,
49
+ config
50
+ }
51
+ });
52
+ this.appActor.subscribe((snapshot) => {
53
+ const stateStr = formatAppSnapshotValue(snapshot.value);
54
+ const prevRunning = this._isRunning.value;
55
+ const nextRunning = snapshot.matches("running");
56
+ const nextSuspended = snapshot.matches({ running: "suspended" });
57
+ this._stateValue.value = stateStr;
58
+ this._isRunning.value = nextRunning;
59
+ this._isSuspended.value = nextSuspended;
60
+ if (nextRunning && !prevRunning) {
61
+ if (!this._pid.value) {
62
+ globalPidCounter += 1;
63
+ this._pid.value = globalPidCounter;
64
+ this._startedAt.value = Date.now();
65
+ }
66
+ void useDesktopHooks().callHook("app:launched", {
67
+ app: this,
68
+ pid: this._pid.value
69
+ });
70
+ useDesktopIPC().emit(
71
+ "process:launched",
72
+ { id: this.id, title: this.config.title, pid: this._pid.value },
73
+ { source: "kernel", severity: "info" }
74
+ );
75
+ }
76
+ if (snapshot.matches("terminating")) {
77
+ const oldPid = this._pid.value;
78
+ this._pid.value = null;
79
+ this._startedAt.value = null;
80
+ this._isRunning.value = false;
81
+ this._isSuspended.value = false;
82
+ try {
83
+ void this.config.onClose?.(this);
84
+ } catch {
85
+ }
86
+ this.appActor.send({ type: "TERMINATED" });
87
+ void useDesktopHooks().callHook("app:terminated", {
88
+ id: this.id,
89
+ title: this.config.title,
90
+ pid: oldPid
91
+ });
92
+ useDesktopIPC().emit(
93
+ "process:terminated",
94
+ { id: this.id, title: this.config.title, pid: oldPid },
95
+ { source: "kernel", severity: "warn" }
96
+ );
97
+ }
98
+ });
99
+ this.appActor.start();
100
+ }
101
+ get windowsOpened() {
102
+ return this.windows;
103
+ }
104
+ getFirstWindowByModel(model) {
105
+ for (const window2 of this.windows.values()) {
106
+ if (window2.model === model) return window2;
107
+ }
108
+ return void 0;
109
+ }
110
+ get pid() {
111
+ return this._pid.value;
112
+ }
113
+ get startedAt() {
114
+ return this._startedAt.value;
115
+ }
116
+ get stateValue() {
117
+ return this._stateValue.value;
118
+ }
119
+ get isRunning() {
120
+ return this._isRunning.value;
121
+ }
122
+ get isSuspended() {
123
+ return this._isSuspended.value;
124
+ }
125
+ get isInitializing() {
126
+ return this._stateValue.value === "initializing";
127
+ }
128
+ get isReady() {
129
+ return this._stateValue.value === "ready";
130
+ }
131
+ async initApplication() {
132
+ this.appActor.send({ type: "LAUNCH" });
133
+ try {
134
+ this.storeWindows = useApplicationWindowsStore(this.id);
135
+ const metaFactory = useApplicationMetaStore(this.id);
136
+ this.storeMeta = metaFactory();
137
+ const commandsService = useDesktopCommands();
138
+ if (this.config.commands) {
139
+ for (const cmdName of Object.keys(this.config.commands)) {
140
+ const termMeta = this.config.terminal?.[cmdName];
141
+ commandsService.register({
142
+ name: cmdName,
143
+ applicationId: this.id,
144
+ description: termMeta?.description ?? this.config.description,
145
+ usage: termMeta?.usage ?? cmdName,
146
+ args: termMeta?.args,
147
+ options: termMeta?.options
148
+ });
149
+ }
150
+ }
151
+ if (this.config.provides) {
152
+ const defaultApps = useDesktopDefaultApps();
153
+ defaultApps.setDefaultApp(
154
+ this.config.provides.name,
155
+ this,
156
+ this.config.provides.entry
157
+ );
158
+ }
159
+ const storeWindows = this.storeWindows;
160
+ if (storeWindows?.$persistedState) {
161
+ await storeWindows.$persistedState.isReady();
162
+ }
163
+ const storeMeta = this.storeMeta;
164
+ if (storeMeta?.$persistedState) {
165
+ await storeMeta.$persistedState.isReady();
166
+ }
167
+ await this.restoreApplication();
168
+ this.appActor.send({ type: "INITIALIZED" });
169
+ await this.config.onReady?.(this);
170
+ } catch (err) {
171
+ this.appActor.send({ type: "INIT_FAILED" });
172
+ console.error(`[@owdproject/nuxt] Failed to init app "${this.id}":`, err);
173
+ }
174
+ }
175
+ /**
176
+ * Reopen the windows persisted in this application's window store. Returns
177
+ * `true` when at least one window was restored. No-op without a persistence
178
+ * adapter (the window store is then always empty at boot).
179
+ */
180
+ async restoreApplication() {
181
+ if (typeof this.config.onRestore === "function") {
182
+ await this.config.onRestore(this);
183
+ }
184
+ const windows = this.storeWindows?.windows;
185
+ if (!windows || Object.keys(windows).length === 0) {
186
+ return false;
187
+ }
188
+ this.restoreWindows();
189
+ return true;
190
+ }
191
+ restoreWindows() {
192
+ const windows = this.storeWindows?.windows;
193
+ if (!windows) return;
194
+ for (const windowId of Object.keys(windows)) {
195
+ if (this.windows.has(windowId)) continue;
196
+ const storedState = windows[windowId];
197
+ if (storedState?.model) {
198
+ this.openWindow(storedState.model, storedState);
199
+ }
200
+ }
201
+ }
202
+ focusWindow(targetWin) {
203
+ const desktopStore = useDesktopStore();
204
+ let previousFocused;
205
+ for (const app of apps.values()) {
206
+ for (const win of app.windows.values()) {
207
+ if (win.state.id !== targetWin.state.id && win.state.focused) {
208
+ previousFocused = win;
209
+ win.setFocus(false);
210
+ void useDesktopHooks().callHook("window:blurred", { window: win });
211
+ }
212
+ }
213
+ }
214
+ const nextZ = desktopStore.incrementPositionZ();
215
+ if (!targetWin.state.position) {
216
+ targetWin.state.position = { x: 100, y: 80, z: nextZ };
217
+ } else {
218
+ targetWin.state.position.z = nextZ;
219
+ }
220
+ targetWin.setFocus(true);
221
+ void useDesktopHooks().callHook("window:focused", {
222
+ window: targetWin,
223
+ previousWindow: previousFocused
224
+ });
225
+ }
226
+ openWindow(model, storedState, meta) {
227
+ const modelConfig = this.config.windows?.[model];
228
+ if (!modelConfig) {
229
+ console.warn(
230
+ `[@owdproject/nuxt] Window model "${model}" is not defined in app "${this.id}".`
231
+ );
232
+ return void 0;
233
+ }
234
+ if (this.config.singleton && this.windows.size > 0) {
235
+ const existing = Array.from(this.windows.values()).find((w) => w.model === model) ?? Array.from(this.windows.values())[0];
236
+ if (meta && existing.meta && typeof existing.meta === "object") {
237
+ Object.assign(existing.meta, meta);
238
+ }
239
+ const workspaceStore2 = useDesktopWorkspaceStore();
240
+ if (existing.state.workspace && existing.state.workspace !== workspaceStore2.active) {
241
+ workspaceStore2.setWorkspace(existing.state.workspace);
242
+ }
243
+ existing.actions.setActive(true);
244
+ existing.actions.bringToFront();
245
+ return existing;
246
+ }
247
+ const openCtx = {
248
+ app: this,
249
+ model,
250
+ config: { ...modelConfig },
251
+ meta,
252
+ cancel: false
253
+ };
254
+ void useDesktopHooks().callHook("window:before-open", openCtx);
255
+ if (openCtx.cancel) {
256
+ return void 0;
257
+ }
258
+ const desktopStore = useDesktopStore();
259
+ const workspaceStore = useDesktopWorkspaceStore();
260
+ const cascadeIndex = this.windows.size;
261
+ const cascadeOffset = cascadeIndex * 28;
262
+ const baseX = openCtx.config.position?.x ?? 120;
263
+ const baseY = openCtx.config.position?.y ?? 90;
264
+ const windowId = storedState?.state?.id || `${this.id}-${model}-${nanoid(6)}`;
265
+ const resolvedStoredState = storedState ?? reactive({
266
+ model,
267
+ meta: reactive({ ...openCtx.meta ?? {} }),
268
+ state: {
269
+ id: windowId,
270
+ createdAt: Date.now(),
271
+ category: openCtx.config.category ?? this.config.category,
272
+ workspace: workspaceStore.active || "workspace-1",
273
+ position: {
274
+ x: baseX + cascadeOffset,
275
+ y: baseY + cascadeOffset,
276
+ z: desktopStore.incrementPositionZ()
277
+ },
278
+ size: {
279
+ width: openCtx.config.size?.width ?? 520,
280
+ height: openCtx.config.size?.height ?? 380,
281
+ minWidth: openCtx.config.size?.minWidth,
282
+ minHeight: openCtx.config.size?.minHeight,
283
+ maxWidth: openCtx.config.size?.maxWidth,
284
+ maxHeight: openCtx.config.size?.maxHeight
285
+ },
286
+ focused: true,
287
+ active: true,
288
+ maximized: Boolean(openCtx.config.maximized),
289
+ minimizable: openCtx.config.minimizable !== false,
290
+ maximizable: openCtx.config.maximizable !== false,
291
+ destroyable: openCtx.config.destroyable !== false,
292
+ draggable: openCtx.config.draggable !== false,
293
+ resizable: openCtx.config.resizable !== false,
294
+ layout: openCtx.config.maximized ? "maximize" : "normal"
295
+ }
296
+ });
297
+ const controller = new WindowController(
298
+ this,
299
+ model,
300
+ openCtx.config,
301
+ resolvedStoredState,
302
+ {
303
+ getWorkarea: () => workspaceStore.workarea
304
+ }
305
+ );
306
+ const origSetLayout = controller.actions.setLayout;
307
+ const enhancedActions = {
308
+ ...controller.actions,
309
+ setLayout: (layout) => {
310
+ const ok = origSetLayout(layout);
311
+ if (ok && layout !== "normal" && layout !== "maximize") {
312
+ const workarea = workspaceStore.workarea;
313
+ const fallbackWorkarea = workarea.width > 0 && workarea.height > 0 ? workarea : {
314
+ x: 0,
315
+ y: 48,
316
+ width: typeof window !== "undefined" ? window.innerWidth : 1280,
317
+ height: typeof window !== "undefined" ? window.innerHeight - 48 : 752
318
+ };
319
+ const rect = computeSnapRect(layout, fallbackWorkarea);
320
+ controller.actions.setPosition({ x: rect.x, y: rect.y });
321
+ controller.actions.setSize({ width: rect.width, height: rect.height });
322
+ }
323
+ if (ok) {
324
+ void useDesktopHooks().callHook("window:layout-change", {
325
+ window: controller,
326
+ layout
327
+ });
328
+ useDesktopIPC().emit(
329
+ "window:layout-change",
330
+ { windowId: controller.state.id, title: controller.title, layout },
331
+ { source: this.id, severity: "info" }
332
+ );
333
+ }
334
+ return ok;
335
+ }
336
+ };
337
+ controller.actions = Object.freeze(enhancedActions);
338
+ const rawWindow = markRaw(controller);
339
+ this.windows.set(windowId, rawWindow);
340
+ this.openWindowCount.value = this.windows.size;
341
+ this.storeWindows?.setWindowState(windowId, resolvedStoredState);
342
+ this.appActor.send({ type: "OPEN_WINDOW" });
343
+ this.focusWindow(rawWindow);
344
+ void useDesktopHooks().callHook("window:opened", {
345
+ window: rawWindow,
346
+ app: this
347
+ });
348
+ useDesktopIPC().emit(
349
+ "window:opened",
350
+ {
351
+ windowId,
352
+ appId: this.id,
353
+ title: rawWindow.title,
354
+ workspace: rawWindow.state.workspace
355
+ },
356
+ { source: this.id, severity: "info" }
357
+ );
358
+ return rawWindow;
359
+ }
360
+ closeWindow(windowId) {
361
+ const win = this.windows.get(windowId);
362
+ if (!win) return;
363
+ const closeCtx = {
364
+ window: win,
365
+ app: this,
366
+ cancel: false
367
+ };
368
+ void useDesktopHooks().callHook("window:before-close", closeCtx);
369
+ if (closeCtx.cancel) return;
370
+ win.dispose();
371
+ this.windows.delete(windowId);
372
+ this.openWindowCount.value = this.windows.size;
373
+ this.storeWindows?.removeWindowState(windowId);
374
+ this.appActor.send({ type: "CLOSE_WINDOW" });
375
+ void useDesktopHooks().callHook("window:closed", {
376
+ windowId,
377
+ app: this
378
+ });
379
+ useDesktopIPC().emit(
380
+ "window:closed",
381
+ { windowId, appId: this.id },
382
+ { source: this.id, severity: "info" }
383
+ );
384
+ }
385
+ closeAllWindows() {
386
+ for (const windowId of Array.from(this.windows.keys())) {
387
+ this.closeWindow(windowId);
388
+ }
389
+ this.storeWindows?.clearWindows();
390
+ }
391
+ setRunning(value) {
392
+ if (value) {
393
+ if (!this.isRunning) {
394
+ this.appActor.send({ type: "LAUNCH" });
395
+ }
396
+ } else if (this.isRunning) {
397
+ this.appActor.send({ type: "CLOSE_APP" });
398
+ }
399
+ }
400
+ suspend() {
401
+ if (!this.isRunning || this.isSuspended) return;
402
+ const ctx = {
403
+ app: this,
404
+ signal: "SIGSTOP",
405
+ cancel: false
406
+ };
407
+ void useDesktopHooks().callHook("app:before-suspend", ctx);
408
+ if (ctx.cancel) return;
409
+ for (const win of this.windows.values()) {
410
+ win.minimize();
411
+ }
412
+ this.appActor.send({ type: "SIGSTOP" });
413
+ void useDesktopHooks().callHook("app:suspended", { app: this });
414
+ useDesktopIPC().emit(
415
+ "process:suspended",
416
+ { id: this.id, pid: this.pid },
417
+ { source: "kernel", severity: "warn" }
418
+ );
419
+ }
420
+ resume() {
421
+ if (!this.isRunning || !this.isSuspended) return;
422
+ const ctx = {
423
+ app: this,
424
+ signal: "SIGCONT",
425
+ cancel: false
426
+ };
427
+ void useDesktopHooks().callHook("app:before-resume", ctx);
428
+ if (ctx.cancel) return;
429
+ this.appActor.send({ type: "SIGCONT" });
430
+ for (const win of this.windows.values()) {
431
+ win.unminimize();
432
+ win.focus();
433
+ }
434
+ void useDesktopHooks().callHook("app:resumed", { app: this });
435
+ useDesktopIPC().emit(
436
+ "process:resumed",
437
+ { id: this.id, pid: this.pid },
438
+ { source: "kernel", severity: "info" }
439
+ );
440
+ }
441
+ sendSignal(signal = "SIGTERM") {
442
+ if (signal === "SIGSTOP") {
443
+ this.suspend();
444
+ return;
445
+ }
446
+ if (signal === "SIGCONT") {
447
+ this.resume();
448
+ return;
449
+ }
450
+ const terminateCtx = {
451
+ app: this,
452
+ signal,
453
+ cancel: false
454
+ };
455
+ void useDesktopHooks().callHook("app:before-terminate", terminateCtx);
456
+ if (terminateCtx.cancel && signal !== "SIGKILL") {
457
+ return;
458
+ }
459
+ for (const win of this.windows.values()) {
460
+ win.dispose();
461
+ }
462
+ this.windows.clear();
463
+ this.openWindowCount.value = 0;
464
+ this.storeWindows?.clearWindows();
465
+ this.appActor.send({ type: signal });
466
+ }
467
+ async execCommand(command) {
468
+ return useDesktopCommands().exec(command);
469
+ }
470
+ }