@dimina-kit/devtools 0.4.0-dev.20260803105710 → 0.4.0-dev.20260828092243
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.
- package/dist/main/api.d.ts +1 -1
- package/dist/main/app/app.js +66 -2
- package/dist/main/index.bundle.js +1454 -540
- package/dist/main/ipc/index.d.ts +3 -0
- package/dist/main/ipc/index.js +3 -0
- package/dist/main/ipc/popover.js +1 -1
- package/dist/main/ipc/project-create.d.ts +15 -0
- package/dist/main/ipc/project-create.js +26 -0
- package/dist/main/ipc/projects.d.ts +1 -1
- package/dist/main/ipc/projects.js +11 -0
- package/dist/main/ipc/session.js +11 -0
- package/dist/main/ipc/settings.js +2 -1
- package/dist/main/ipc/simulator-module.d.ts +4 -3
- package/dist/main/ipc/simulator-module.js +4 -5
- package/dist/main/ipc/tooltip.d.ts +13 -0
- package/dist/main/ipc/tooltip.js +28 -0
- package/dist/main/ipc/views.d.ts +15 -1
- package/dist/main/ipc/views.js +61 -4
- package/dist/main/runtime/miniapp-runtime.d.ts +87 -19
- package/dist/main/services/layout/index.d.ts +11 -0
- package/dist/main/services/layout/index.js +23 -0
- package/dist/main/services/network-forward/frontend-dispatch.js +2 -1
- package/dist/main/services/notifications/renderer-notifier.d.ts +32 -1
- package/dist/main/services/notifications/renderer-notifier.js +29 -1
- package/dist/main/services/projects/project-repository.d.ts +4 -1
- package/dist/main/services/projects/project-repository.js +63 -5
- package/dist/main/services/simulator-current-page/index.d.ts +5 -3
- package/dist/main/services/simulator-current-page/index.js +8 -1
- package/dist/main/services/update/update-manager.d.ts +17 -3
- package/dist/main/services/update/update-manager.js +25 -6
- package/dist/main/services/views/clear-console-filter.d.ts +44 -0
- package/dist/main/services/views/clear-console-filter.js +86 -0
- package/dist/main/services/views/console-filter-test-fixtures.d.ts +94 -0
- package/dist/main/services/views/console-filter-test-fixtures.js +82 -0
- package/dist/main/services/views/console-filter.d.ts +79 -130
- package/dist/main/services/views/console-filter.js +140 -183
- package/dist/main/services/views/devtools-tabs.d.ts +24 -4
- package/dist/main/services/views/devtools-tabs.js +40 -21
- package/dist/main/services/views/host-dialog-port-channel.d.ts +18 -0
- package/dist/main/services/views/host-dialog-port-channel.js +15 -0
- package/dist/main/services/views/host-dialog-session-runtime.d.ts +10 -0
- package/dist/main/services/views/host-dialog-session-runtime.js +17 -0
- package/dist/main/services/views/host-dialog-view.d.ts +95 -0
- package/dist/main/services/views/host-dialog-view.js +147 -0
- package/dist/main/services/views/host-sidebar-port-channel.d.ts +18 -0
- package/dist/main/services/views/host-sidebar-port-channel.js +15 -0
- package/dist/main/services/views/host-sidebar-session-runtime.d.ts +10 -0
- package/dist/main/services/views/host-sidebar-session-runtime.js +17 -0
- package/dist/main/services/views/host-sidebar-view.d.ts +59 -0
- package/dist/main/services/views/host-sidebar-view.js +44 -0
- package/dist/main/services/views/host-slot-port-channel.d.ts +107 -0
- package/dist/main/services/views/host-slot-port-channel.js +261 -0
- package/dist/main/services/views/host-slot-session-runtime.d.ts +40 -0
- package/dist/main/services/views/host-slot-session-runtime.js +50 -0
- package/dist/main/services/views/host-slot-view.d.ts +109 -0
- package/dist/main/services/views/host-slot-view.js +147 -0
- package/dist/main/services/views/host-toolbar-port-channel.d.ts +6 -91
- package/dist/main/services/views/host-toolbar-port-channel.js +10 -243
- package/dist/main/services/views/host-toolbar-session-runtime.d.ts +5 -30
- package/dist/main/services/views/host-toolbar-session-runtime.js +9 -47
- package/dist/main/services/views/host-toolbar-view.d.ts +34 -7
- package/dist/main/services/views/host-toolbar-view.js +30 -237
- package/dist/main/services/views/managed-web-contents-view.d.ts +48 -0
- package/dist/main/services/views/managed-web-contents-view.js +123 -0
- package/dist/main/services/views/native-simulator-devtools-host.js +64 -45
- package/dist/main/services/views/native-simulator-view.js +6 -24
- package/dist/main/services/views/native-view-tree.d.ts +25 -0
- package/dist/main/services/views/native-view-tree.js +69 -0
- package/dist/main/services/views/overlay-panels-view.d.ts +50 -4
- package/dist/main/services/views/overlay-panels-view.js +226 -108
- package/dist/main/services/views/placement-reconciler.d.ts +18 -18
- package/dist/main/services/views/placement-reconciler.js +91 -29
- package/dist/main/services/views/placement-test-driver.d.ts +27 -0
- package/dist/main/services/views/placement-test-driver.js +29 -0
- package/dist/main/services/views/view-manager-devtools-host-test-fixtures.js +3 -1
- package/dist/main/services/views/view-manager.d.ts +14 -86
- package/dist/main/services/views/view-manager.js +41 -4
- package/dist/main/services/views/workbench-view.js +27 -20
- package/dist/main/services/workbench-coi-server.d.ts +11 -0
- package/dist/main/services/workbench-coi-server.js +32 -0
- package/dist/main/services/workspace/rebuild-status.d.ts +21 -8
- package/dist/main/services/workspace/rebuild-status.js +24 -8
- package/dist/main/utils/paths.d.ts +4 -0
- package/dist/main/utils/paths.js +4 -0
- package/dist/main/utils/sender-policy.d.ts +1 -1
- package/dist/main/utils/sender-policy.js +16 -1
- package/dist/main/utils/theme.d.ts +7 -2
- package/dist/main/utils/theme.js +8 -3
- package/dist/native-host/common/common.js +65 -62
- package/dist/native-host/container/pageFrame.css +1 -1
- package/dist/native-host/render/render.js +3226 -2898
- package/dist/native-host/service/service.js +2 -2
- package/dist/preload/runtime/host-dialog-advertiser.d.ts +22 -0
- package/dist/preload/runtime/host-dialog-advertiser.js +37 -0
- package/dist/preload/runtime/host-dialog-port.d.ts +44 -0
- package/dist/preload/runtime/host-dialog-port.js +53 -0
- package/dist/preload/runtime/host-dialog-runtime.d.ts +28 -0
- package/dist/preload/runtime/host-dialog-runtime.js +36 -0
- package/dist/preload/runtime/host-sidebar-advertiser.d.ts +19 -0
- package/dist/preload/runtime/host-sidebar-advertiser.js +35 -0
- package/dist/preload/runtime/host-sidebar-port.d.ts +44 -0
- package/dist/preload/runtime/host-sidebar-port.js +53 -0
- package/dist/preload/runtime/host-sidebar-runtime.d.ts +28 -0
- package/dist/preload/runtime/host-sidebar-runtime.js +36 -0
- package/dist/preload/runtime/host-slot-port-bridge.d.ts +18 -0
- package/dist/preload/runtime/host-slot-port-bridge.js +112 -0
- package/dist/preload/runtime/host-toolbar-advertiser.d.ts +5 -13
- package/dist/preload/runtime/host-toolbar-advertiser.js +18 -38
- package/dist/preload/runtime/host-toolbar-port.d.ts +9 -0
- package/dist/preload/runtime/host-toolbar-port.js +11 -95
- package/dist/preload/runtime/wait-for-slot-root.d.ts +20 -0
- package/dist/preload/runtime/wait-for-slot-root.js +52 -0
- package/dist/preload/windows/host-dialog-runtime.cjs +353 -0
- package/dist/preload/windows/host-dialog-runtime.cjs.map +7 -0
- package/dist/preload/windows/host-dialog-runtime.d.ts +2 -0
- package/dist/preload/windows/host-dialog-runtime.js +13 -0
- package/dist/preload/windows/host-sidebar-runtime.cjs +354 -0
- package/dist/preload/windows/host-sidebar-runtime.cjs.map +7 -0
- package/dist/preload/windows/host-sidebar-runtime.d.ts +2 -0
- package/dist/preload/windows/host-sidebar-runtime.js +13 -0
- package/dist/preload/windows/host-toolbar-runtime.cjs +134 -51
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +3 -3
- package/dist/preload/windows/main.cjs +3176 -14
- package/dist/preload/windows/main.cjs.map +4 -4
- package/dist/preload/windows/main.css +428 -0
- package/dist/preload/windows/main.css.map +7 -0
- package/dist/preload/windows/simulator.cjs +5 -2
- package/dist/preload/windows/simulator.cjs.map +2 -2
- package/dist/preload/windows/simulator.js +5 -2
- package/dist/renderer/assets/button-DsNqZm7o.js +2 -0
- package/dist/renderer/assets/constants-D7DfVqMp.js +2 -0
- package/dist/renderer/assets/constants-D8zsejFq.js +2 -0
- package/dist/renderer/assets/createLucideIcon-CYJeT1ji.js +2 -0
- package/dist/renderer/assets/dialog-pT4qWmka.js +46 -0
- package/dist/renderer/assets/dist-o70xmpc1.js +2 -0
- package/dist/renderer/assets/hostSidebarDefault-NvGZlE9O.js +2 -0
- package/dist/renderer/assets/index-zErhG3ta.js +5 -0
- package/dist/renderer/assets/input-4QxTXMZN.js +2 -0
- package/dist/renderer/assets/ipc-channels-overlays-Blr5TNoB.js +2 -0
- package/dist/renderer/assets/jsx-runtime-B-3rq1y5.css +1 -0
- package/dist/renderer/assets/jsx-runtime-CqVdW3eg.js +9 -0
- package/dist/renderer/assets/popover-CJiSWwuE.js +2 -0
- package/dist/renderer/assets/project-api-DZ1Zi6EC.js +2 -0
- package/dist/renderer/assets/projectCreateDialog-DMWNhw_1.js +2 -0
- package/dist/renderer/assets/select-C86pNcsu.js +2 -0
- package/dist/renderer/assets/settings-BoI8mLT1.js +2 -0
- package/dist/renderer/assets/settings-api-Bs_g4NHs.js +2 -0
- package/dist/renderer/assets/settings-tab-bar-DHLLygqv.js +2 -0
- package/dist/renderer/assets/tooltip-BhAyY0T4.js +2 -0
- package/dist/renderer/assets/types-YYjkvane.js +2 -0
- package/dist/renderer/assets/updateDialog-DPum3wx1.js +2 -0
- package/dist/renderer/assets/utils-kfQov6Pa.js +2 -0
- package/dist/renderer/assets/view-api-DFhb2R8-.js +2 -0
- package/dist/renderer/assets/workbenchSettings-DrajRQUk.js +8 -0
- package/dist/renderer/entries/host-sidebar-default/index.html +21 -0
- package/dist/renderer/entries/main/index.html +15 -7
- package/dist/renderer/entries/popover/index.html +10 -6
- package/dist/renderer/entries/project-create-dialog/index.html +27 -0
- package/dist/renderer/entries/settings/index.html +10 -5
- package/dist/renderer/entries/tooltip/index.html +21 -0
- package/dist/renderer/entries/update-dialog/index.html +25 -0
- package/dist/renderer/entries/workbench-settings/index.html +11 -5
- package/dist/service-host/preload.cjs +10 -0
- package/dist/service-host/sync-impls/menu-button-geometry.js +1 -0
- package/dist/shared/constants.d.ts +22 -0
- package/dist/shared/constants.js +22 -0
- package/dist/shared/ipc-channels-overlays.d.ts +156 -0
- package/dist/shared/ipc-channels-overlays.js +186 -0
- package/dist/shared/ipc-channels.d.ts +1 -67
- package/dist/shared/ipc-channels.js +9 -81
- package/dist/shared/ipc-schemas.d.ts +52 -0
- package/dist/shared/ipc-schemas.js +64 -0
- package/dist/shared/simulator-route.d.ts +8 -0
- package/dist/shared/simulator-route.js +15 -0
- package/dist/shared/types.d.ts +17 -0
- package/dist/shared/view-ids.d.ts +9 -0
- package/dist/shared/view-ids.js +21 -0
- package/dist/simulator/assets/device-shell-CmtM1QxP.js +2 -0
- package/dist/simulator/assets/device-shell-iFZo1igL.css +1 -0
- package/dist/simulator/assets/{simulator-COIE6R49.js → simulator-CIobn3Mh.js} +6 -6
- package/dist/simulator/assets/{simulator-mini-app-BLn7XV8e.js → simulator-mini-app-CRe6n9br.js} +2 -2
- package/dist/simulator/assets/simulator-ui-BupATgKo.css +1 -0
- package/dist/simulator/assets/simulator-ui-C_cP602X.js +2 -0
- package/dist/simulator/simulator.html +3 -2
- package/dist/vscode-workbench/assets/__vite-browser-external-Bc1vizTf.js +1 -0
- package/dist/vscode-workbench/assets/{dist-oHcwN53f.js → dist-CMfmHflW.js} +3 -3
- package/dist/vscode-workbench/assets/{iconv-lite-umd-CLMLpdGm.js → iconv-lite-umd-Bx8CgaZq.js} +1 -1
- package/dist/vscode-workbench/assets/{index-BE3UJdoH.js → index-CdG6YWhW.js} +436 -436
- package/dist/vscode-workbench/assets/{jschardet-BICW8PLJ.js → jschardet-M0qgd2lN.js} +1 -1
- package/dist/vscode-workbench/index.html +21 -1
- package/package.json +9 -8
- package/dist/main/services/views/destroy-child-view.d.ts +0 -9
- package/dist/main/services/views/destroy-child-view.js +0 -23
- package/dist/renderer/assets/constants-EAMiwL9_.js +0 -2
- package/dist/renderer/assets/index-BBg3YI5b.js +0 -49
- package/dist/renderer/assets/input-xdmfv-eH.js +0 -2
- package/dist/renderer/assets/ipc-transport-B3EpmfNS.js +0 -9
- package/dist/renderer/assets/ipc-transport-Blac3sOj.css +0 -1
- package/dist/renderer/assets/popover-B88e2hkg.js +0 -2
- package/dist/renderer/assets/select-CD9CJyhI.js +0 -2
- package/dist/renderer/assets/settings-44hf0QtO.js +0 -2
- package/dist/renderer/assets/settings-api-pJKPuP1M.js +0 -2
- package/dist/renderer/assets/workbenchSettings-DKD5U1Ql.js +0 -8
- package/dist/simulator/assets/device-shell-Cw7c-IkG.js +0 -2
- package/dist/simulator/assets/device-shell-DbC5ccs8.css +0 -1
- package/dist/simulator/assets/jsx-runtime-DkKmJyBb.js +0 -2
- package/dist/simulator/device-shell/menu-button-geometry.js +0 -18
- package/dist/vscode-workbench/assets/__vite-browser-external-BON7qP59.js +0 -1
|
@@ -1,150 +1,268 @@
|
|
|
1
1
|
import { WebContentsView } from 'electron';
|
|
2
|
-
import
|
|
2
|
+
import { createOverlayPanel } from '@dimina-kit/electron-deck/main';
|
|
3
3
|
import { mainPreloadPath } from '../../utils/paths.js';
|
|
4
4
|
import { applyNavigationHardening } from '../../windows/navigation-hardening.js';
|
|
5
5
|
import * as layout from '../layout/index.js';
|
|
6
6
|
import { HEADER_H } from '../../../shared/constants.js';
|
|
7
7
|
import { VIEW_ID, VIEW_LAYER } from '../../../shared/view-ids.js';
|
|
8
|
-
import {
|
|
8
|
+
import { UpdateChannel } from '../../../shared/ipc-channels-overlays.js';
|
|
9
9
|
export function createOverlayPanelsView(ctx, reconciler, deps) {
|
|
10
|
-
let settingsView = null;
|
|
11
|
-
let popoverView = null;
|
|
12
10
|
function overlayHeaderHeight() {
|
|
13
11
|
return HEADER_H + deps.getHostToolbarHeight();
|
|
14
12
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
30
|
-
reconciler.reconcileNow();
|
|
13
|
+
function overlayDesiredSetter(viewId, layer) {
|
|
14
|
+
return (bounds) => {
|
|
15
|
+
if (bounds === null) {
|
|
16
|
+
reconciler.deleteOverlayDesired(viewId);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
reconciler.setOverlayDesired(viewId, {
|
|
20
|
+
viewId,
|
|
21
|
+
placement: { visible: true, bounds },
|
|
22
|
+
layer,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
reconciler.reconcileNow();
|
|
26
|
+
};
|
|
31
27
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
reconciler.
|
|
28
|
+
const settingsPanel = createOverlayPanel({
|
|
29
|
+
electron: { createWebContentsView: (opts) => new WebContentsView(opts) },
|
|
30
|
+
rendererDir: ctx.rendererDir,
|
|
31
|
+
entry: 'entries/settings/index.html',
|
|
32
|
+
webPreferences: {
|
|
33
|
+
nodeIntegration: false,
|
|
34
|
+
contextIsolation: true,
|
|
35
|
+
sandbox: false,
|
|
36
|
+
preload: mainPreloadPath,
|
|
37
|
+
},
|
|
38
|
+
hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
|
|
39
|
+
setDesired: overlayDesiredSetter(VIEW_ID.settings, VIEW_LAYER.settings),
|
|
40
|
+
registerView: (getView) => reconciler.registerView(VIEW_ID.settings, { getView }),
|
|
41
|
+
destroyView: (view) => reconciler.destroyView(VIEW_ID.settings, view),
|
|
42
|
+
readyMode: 'manual',
|
|
43
|
+
});
|
|
44
|
+
const popoverPanel = createOverlayPanel({
|
|
45
|
+
electron: { createWebContentsView: (opts) => new WebContentsView(opts) },
|
|
46
|
+
rendererDir: ctx.rendererDir,
|
|
47
|
+
entry: 'entries/popover/index.html',
|
|
48
|
+
webPreferences: {
|
|
49
|
+
nodeIntegration: false,
|
|
50
|
+
contextIsolation: true,
|
|
51
|
+
sandbox: false,
|
|
52
|
+
preload: mainPreloadPath,
|
|
53
|
+
},
|
|
54
|
+
hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
|
|
55
|
+
setDesired: overlayDesiredSetter(VIEW_ID.popover, VIEW_LAYER.popover),
|
|
56
|
+
registerView: (getView) => reconciler.registerView(VIEW_ID.popover, { getView }),
|
|
57
|
+
destroyView: (view) => reconciler.destroyView(VIEW_ID.popover, view),
|
|
58
|
+
pushData: (view, data) => ctx.notify.popoverInit(view, data),
|
|
59
|
+
readyMode: 'manual',
|
|
60
|
+
});
|
|
61
|
+
const tooltipPanel = createOverlayPanel({
|
|
62
|
+
electron: { createWebContentsView: (opts) => new WebContentsView(opts) },
|
|
63
|
+
rendererDir: ctx.rendererDir,
|
|
64
|
+
entry: 'entries/tooltip/index.html',
|
|
65
|
+
webPreferences: {
|
|
66
|
+
nodeIntegration: false,
|
|
67
|
+
contextIsolation: true,
|
|
68
|
+
sandbox: false,
|
|
69
|
+
preload: mainPreloadPath,
|
|
70
|
+
},
|
|
71
|
+
hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
|
|
72
|
+
setDesired: overlayDesiredSetter(VIEW_ID.tooltip, VIEW_LAYER.tooltip),
|
|
73
|
+
registerView: (getView) => reconciler.registerView(VIEW_ID.tooltip, { getView }),
|
|
74
|
+
prepareView: (view) => {
|
|
75
|
+
const [width = 0, height = 0] = ctx.windows.mainWindow.getContentSize();
|
|
76
|
+
reconciler.prepareView(VIEW_ID.tooltip, view, {
|
|
77
|
+
x: 0,
|
|
78
|
+
y: 0,
|
|
79
|
+
width: Math.max(1, width),
|
|
80
|
+
height: Math.max(1, height),
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
destroyView: (view) => reconciler.destroyView(VIEW_ID.tooltip, view),
|
|
84
|
+
pushData: (view, data) => ctx.notify.tooltipInit(view, data),
|
|
85
|
+
readyMode: 'manual',
|
|
86
|
+
});
|
|
87
|
+
/**
|
|
88
|
+
* Both devtools-owned dialog panels occupy the full main-window content
|
|
89
|
+
* rect (they render their own centered card + backdrop), so unlike
|
|
90
|
+
* settings/popover/tooltip they need no anchor-derived bounds computation —
|
|
91
|
+
* just the window's current content size, recomputed on every show/resize.
|
|
92
|
+
*/
|
|
93
|
+
function fullWindowBounds() {
|
|
94
|
+
const [width = 0, height = 0] = ctx.windows.mainWindow.getContentSize();
|
|
95
|
+
return { x: 0, y: 0, width: Math.max(1, width), height: Math.max(1, height) };
|
|
45
96
|
}
|
|
97
|
+
const projectCreateDialogPanel = createOverlayPanel({
|
|
98
|
+
electron: { createWebContentsView: (opts) => new WebContentsView(opts) },
|
|
99
|
+
rendererDir: ctx.rendererDir,
|
|
100
|
+
entry: 'entries/project-create-dialog/index.html',
|
|
101
|
+
webPreferences: {
|
|
102
|
+
nodeIntegration: false,
|
|
103
|
+
contextIsolation: true,
|
|
104
|
+
sandbox: false,
|
|
105
|
+
preload: mainPreloadPath,
|
|
106
|
+
},
|
|
107
|
+
hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
|
|
108
|
+
setDesired: overlayDesiredSetter(VIEW_ID.projectCreateDialog, VIEW_LAYER.dialog),
|
|
109
|
+
registerView: (getView) => reconciler.registerView(VIEW_ID.projectCreateDialog, { getView }),
|
|
110
|
+
destroyView: (view) => reconciler.destroyView(VIEW_ID.projectCreateDialog, view),
|
|
111
|
+
pushData: (view, data) => ctx.notify.projectCreateInit(view, data),
|
|
112
|
+
readyMode: 'manual',
|
|
113
|
+
});
|
|
114
|
+
const updateDialogPanel = createOverlayPanel({
|
|
115
|
+
electron: { createWebContentsView: (opts) => new WebContentsView(opts) },
|
|
116
|
+
rendererDir: ctx.rendererDir,
|
|
117
|
+
entry: 'entries/update-dialog/index.html',
|
|
118
|
+
webPreferences: {
|
|
119
|
+
nodeIntegration: false,
|
|
120
|
+
contextIsolation: true,
|
|
121
|
+
sandbox: false,
|
|
122
|
+
preload: mainPreloadPath,
|
|
123
|
+
},
|
|
124
|
+
hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
|
|
125
|
+
setDesired: overlayDesiredSetter(VIEW_ID.updateDialog, VIEW_LAYER.dialog),
|
|
126
|
+
registerView: (getView) => reconciler.registerView(VIEW_ID.updateDialog, { getView }),
|
|
127
|
+
destroyView: (view) => reconciler.destroyView(VIEW_ID.updateDialog, view),
|
|
128
|
+
pushData: (view, data) => ctx.notify.updateAvailable(view, data),
|
|
129
|
+
readyMode: 'manual',
|
|
130
|
+
});
|
|
131
|
+
let tooltipRequestId = 0;
|
|
132
|
+
let activeTooltip = null;
|
|
46
133
|
async function showSettings() {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
nodeIntegration: false,
|
|
51
|
-
contextIsolation: true,
|
|
52
|
-
sandbox: false,
|
|
53
|
-
preload: mainPreloadPath,
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
// Overlay loads mainPreloadPath, so the same navigation rules as the
|
|
57
|
-
// main window apply — see navigation-hardening.ts.
|
|
58
|
-
applyNavigationHardening(settingsView.webContents, ctx.rendererDir);
|
|
59
|
-
// Transparent backing: the settings view now spans the whole content area
|
|
60
|
-
// (computeSettingsBounds) and its renderer paints a transparent backdrop +
|
|
61
|
-
// an opaque right-side panel, so the underlying editor/simulator show
|
|
62
|
-
// through and a backdrop click closes the overlay (mirrors the popover).
|
|
63
|
-
settingsView.setBackgroundColor('#00000000');
|
|
64
|
-
await settingsView.webContents.loadFile(path.join(ctx.rendererDir, 'entries/settings/index.html'));
|
|
65
|
-
}
|
|
66
|
-
applySettingsBounds();
|
|
134
|
+
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
135
|
+
settingsPanel.show(undefined, layout.computeSettingsBounds(w, h, overlayHeaderHeight()));
|
|
136
|
+
await settingsPanel.whenReady();
|
|
67
137
|
}
|
|
68
138
|
function hideSettings() {
|
|
69
|
-
|
|
70
|
-
reconciler.reconcileNow();
|
|
139
|
+
settingsPanel.hide();
|
|
71
140
|
}
|
|
72
141
|
function showPopover(data) {
|
|
142
|
+
// Popover carries no state across opens (always fresh init data) — force a
|
|
143
|
+
// brand-new instance rather than reusing/repositioning a live one (and
|
|
144
|
+
// notify like any other close, via the shared hidePopover()).
|
|
73
145
|
hidePopover();
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
nodeIntegration: false,
|
|
77
|
-
contextIsolation: true,
|
|
78
|
-
sandbox: false,
|
|
79
|
-
preload: mainPreloadPath,
|
|
80
|
-
},
|
|
81
|
-
});
|
|
82
|
-
// Popover overlay loads mainPreloadPath — same navigation rules apply.
|
|
83
|
-
applyNavigationHardening(popover.webContents, ctx.rendererDir);
|
|
84
|
-
popoverView = popover;
|
|
85
|
-
popover.setBackgroundColor('#00000000');
|
|
86
|
-
applyPopoverBounds();
|
|
87
|
-
popover.webContents.once('did-finish-load', () => {
|
|
88
|
-
ctx.notify.popoverInit(popover, data);
|
|
89
|
-
});
|
|
90
|
-
popover.webContents.loadFile(path.join(ctx.rendererDir, 'entries/popover/index.html'));
|
|
146
|
+
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
147
|
+
popoverPanel.show(data, layout.computePopoverBounds(w, h, overlayHeaderHeight()));
|
|
91
148
|
}
|
|
92
149
|
function hidePopover() {
|
|
93
|
-
if (!
|
|
150
|
+
if (!popoverPanel.isPresent())
|
|
94
151
|
return;
|
|
152
|
+
popoverPanel.destroy();
|
|
95
153
|
reconciler.deleteOverlayDesired(VIEW_ID.popover);
|
|
96
|
-
// Destroy the WCV first (removeChildView + close), THEN reconcile: the detach
|
|
97
|
-
// op then finds the view already gone and does not double-removeChildView.
|
|
98
|
-
destroyChildView(ctx.windows.mainWindow, popoverView);
|
|
99
|
-
popoverView = null;
|
|
100
154
|
reconciler.reconcileNow();
|
|
101
155
|
ctx.notify.popoverClosed();
|
|
102
156
|
}
|
|
157
|
+
function prepareTooltip() {
|
|
158
|
+
tooltipPanel.prepare();
|
|
159
|
+
}
|
|
160
|
+
function showTooltip(data) {
|
|
161
|
+
const requestId = ++tooltipRequestId;
|
|
162
|
+
activeTooltip = { requestId, anchor: data.anchor };
|
|
163
|
+
const [contentWidth = 0] = ctx.windows.mainWindow.getContentSize();
|
|
164
|
+
tooltipPanel.show({
|
|
165
|
+
requestId,
|
|
166
|
+
text: data.text,
|
|
167
|
+
maxWidth: layout.computeTooltipMaxWidth(contentWidth),
|
|
168
|
+
}, null);
|
|
169
|
+
}
|
|
170
|
+
function hideTooltip() {
|
|
171
|
+
activeTooltip = null;
|
|
172
|
+
tooltipPanel.hide();
|
|
173
|
+
}
|
|
174
|
+
function showProjectCreateDialog(data) {
|
|
175
|
+
projectCreateDialogPanel.show(data, fullWindowBounds());
|
|
176
|
+
}
|
|
177
|
+
function hideProjectCreateDialog() {
|
|
178
|
+
projectCreateDialogPanel.hide();
|
|
179
|
+
}
|
|
180
|
+
function showUpdateDialog(data) {
|
|
181
|
+
updateDialogPanel.show(data, fullWindowBounds());
|
|
182
|
+
}
|
|
183
|
+
function hideUpdateDialog() {
|
|
184
|
+
updateDialogPanel.hide();
|
|
185
|
+
}
|
|
186
|
+
function notifyUpdateDownloadProgress(percent) {
|
|
187
|
+
const wc = updateDialogPanel.getWebContents();
|
|
188
|
+
if (!wc)
|
|
189
|
+
return;
|
|
190
|
+
wc.send(UpdateChannel.DownloadProgress, { percent });
|
|
191
|
+
}
|
|
192
|
+
function markOverlayReady(webContentsId) {
|
|
193
|
+
settingsPanel.markReady(webContentsId);
|
|
194
|
+
popoverPanel.markReady(webContentsId);
|
|
195
|
+
tooltipPanel.markReady(webContentsId);
|
|
196
|
+
projectCreateDialogPanel.markReady(webContentsId);
|
|
197
|
+
updateDialogPanel.markReady(webContentsId);
|
|
198
|
+
}
|
|
199
|
+
function applyTooltipMeasurement(webContentsId, measurement) {
|
|
200
|
+
const active = activeTooltip;
|
|
201
|
+
if (!active || active.requestId !== measurement.requestId)
|
|
202
|
+
return;
|
|
203
|
+
if (tooltipPanel.getWebContentsId() !== webContentsId)
|
|
204
|
+
return;
|
|
205
|
+
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
206
|
+
tooltipPanel.reposition(layout.computeTooltipBounds(active.anchor, w, h, measurement));
|
|
207
|
+
}
|
|
103
208
|
function reapplyPresentOverlays() {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
209
|
+
// Fire-and-forget re-trigger — a crash between this call and the panel
|
|
210
|
+
// becoming ready now rejects whenReady() (see overlay-panel.ts teardown);
|
|
211
|
+
// handleViewBroken() already logs it, nothing more to do here.
|
|
212
|
+
if (settingsPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.settings)) {
|
|
213
|
+
showSettings().catch(() => { });
|
|
214
|
+
}
|
|
215
|
+
if (popoverPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.popover)) {
|
|
216
|
+
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
217
|
+
popoverPanel.reposition(layout.computePopoverBounds(w, h, overlayHeaderHeight()));
|
|
218
|
+
}
|
|
219
|
+
if (projectCreateDialogPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.projectCreateDialog)) {
|
|
220
|
+
projectCreateDialogPanel.reposition(fullWindowBounds());
|
|
221
|
+
}
|
|
222
|
+
if (updateDialogPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.updateDialog)) {
|
|
223
|
+
updateDialogPanel.reposition(fullWindowBounds());
|
|
224
|
+
}
|
|
108
225
|
}
|
|
109
226
|
function applySettingsBoundsIfPresent() {
|
|
110
|
-
|
|
111
|
-
|
|
227
|
+
// See reapplyPresentOverlays() above for why this swallows a rejection.
|
|
228
|
+
if (settingsPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.settings)) {
|
|
229
|
+
showSettings().catch(() => { });
|
|
230
|
+
}
|
|
112
231
|
}
|
|
113
232
|
function destroySettings() {
|
|
114
|
-
|
|
115
|
-
|
|
233
|
+
activeTooltip = null;
|
|
234
|
+
settingsPanel.destroy();
|
|
235
|
+
tooltipPanel.destroy();
|
|
236
|
+
}
|
|
237
|
+
function destroyDialogs() {
|
|
238
|
+
projectCreateDialogPanel.destroy();
|
|
239
|
+
updateDialogPanel.destroy();
|
|
116
240
|
}
|
|
117
|
-
reconciler.registerView(VIEW_ID.settings, { getView: () => settingsView });
|
|
118
|
-
reconciler.registerView(VIEW_ID.popover, { getView: () => popoverView });
|
|
119
241
|
return {
|
|
120
242
|
showSettings,
|
|
121
243
|
hideSettings,
|
|
122
244
|
showPopover,
|
|
123
245
|
hidePopover,
|
|
246
|
+
prepareTooltip,
|
|
247
|
+
showTooltip,
|
|
248
|
+
hideTooltip,
|
|
249
|
+
markOverlayReady,
|
|
250
|
+
applyTooltipMeasurement,
|
|
251
|
+
showProjectCreateDialog,
|
|
252
|
+
hideProjectCreateDialog,
|
|
253
|
+
showUpdateDialog,
|
|
254
|
+
hideUpdateDialog,
|
|
255
|
+
notifyUpdateDownloadProgress,
|
|
124
256
|
reapplyPresentOverlays,
|
|
125
257
|
applySettingsBoundsIfPresent,
|
|
126
258
|
destroySettings,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
getSettingsWebContentsId: () => {
|
|
135
|
-
if (!settingsView)
|
|
136
|
-
return null;
|
|
137
|
-
if (settingsView.webContents.isDestroyed())
|
|
138
|
-
return null;
|
|
139
|
-
return settingsView.webContents.id;
|
|
140
|
-
},
|
|
141
|
-
getPopoverWebContentsId: () => {
|
|
142
|
-
if (!popoverView)
|
|
143
|
-
return null;
|
|
144
|
-
if (popoverView.webContents.isDestroyed())
|
|
145
|
-
return null;
|
|
146
|
-
return popoverView.webContents.id;
|
|
147
|
-
},
|
|
259
|
+
destroyDialogs,
|
|
260
|
+
getSettingsWebContents: () => settingsPanel.getWebContents(),
|
|
261
|
+
getSettingsWebContentsId: () => settingsPanel.getWebContentsId(),
|
|
262
|
+
getPopoverWebContentsId: () => popoverPanel.getWebContentsId(),
|
|
263
|
+
getTooltipWebContentsId: () => tooltipPanel.getWebContentsId(),
|
|
264
|
+
getProjectCreateDialogWebContentsId: () => projectCreateDialogPanel.getWebContentsId(),
|
|
265
|
+
getUpdateDialogWebContentsId: () => updateDialogPanel.getWebContentsId(),
|
|
148
266
|
};
|
|
149
267
|
}
|
|
150
268
|
//# sourceMappingURL=overlay-panels-view.js.map
|
|
@@ -12,8 +12,6 @@ import type { ViewManagerContext } from './view-manager.js';
|
|
|
12
12
|
export interface ViewSlot {
|
|
13
13
|
/** The live WebContentsView for this slot, or null when not yet created. */
|
|
14
14
|
getView(): WebContentsView | null;
|
|
15
|
-
/** Record whether the view is currently added to the contentView. */
|
|
16
|
-
setAdded?(added: boolean): void;
|
|
17
15
|
/**
|
|
18
16
|
* When true, force the desired placement to hidden — the view-creation site
|
|
19
17
|
* has not produced the WCV yet, so the reconciler must never record an attach
|
|
@@ -21,12 +19,6 @@ export interface ViewSlot {
|
|
|
21
19
|
* to re-open the gate.
|
|
22
20
|
*/
|
|
23
21
|
gateHidden?(): boolean;
|
|
24
|
-
/**
|
|
25
|
-
* Run before the generic attach. Return true when the slot fully handled the
|
|
26
|
-
* attach itself (e.g. a lazy async load that adds the view on completion), so
|
|
27
|
-
* the reconciler must NOT addChildView here.
|
|
28
|
-
*/
|
|
29
|
-
beforeAttach?(): boolean;
|
|
30
22
|
/** Lazily create the view on attach (host-toolbar); used instead of getView. */
|
|
31
23
|
ensureView?(): WebContentsView | null;
|
|
32
24
|
/** Domain-specific setBounds (simulator zoom rides here). */
|
|
@@ -44,8 +36,10 @@ export interface ViewSlot {
|
|
|
44
36
|
* settings/popover are main-owned and live in `overlayDesired`. Any change
|
|
45
37
|
* merges the two, runs the pure reconcile core, and applies the ordered ops
|
|
46
38
|
* through `viewTarget`. `epochCounter` is a single monotonic tick — main is the
|
|
47
|
-
* only (serial) reconcile caller, so the core's stale guard passes by
|
|
48
|
-
* construction; `rendererGeneration`
|
|
39
|
+
* only (serial) reconcile caller, so the core's stale-epoch guard passes by
|
|
40
|
+
* construction; `rendererGeneration` is the high-water mark that drives both
|
|
41
|
+
* the reset on a genuinely newer generation and the hard rejection of a
|
|
42
|
+
* snapshot from behind it (see `setPlacementSnapshot`).
|
|
49
43
|
*/
|
|
50
44
|
export interface PlacementReconciler {
|
|
51
45
|
registerView(viewId: string, slot: ViewSlot): void;
|
|
@@ -55,19 +49,25 @@ export interface PlacementReconciler {
|
|
|
55
49
|
* truth for every managed native view's bounds/visibility/z-order.
|
|
56
50
|
*/
|
|
57
51
|
setPlacementSnapshot(snapshot: PlacementSnapshot<DevtoolsExtra>): void;
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
* level-triggered core still records the old instance as attached and never
|
|
63
|
-
* emits the attach op for the replacement — a sticky invisible view).
|
|
64
|
-
*/
|
|
65
|
-
forgetActual(viewId: string): void;
|
|
52
|
+
/** Size a detached view for renderer-side intrinsic measurement. */
|
|
53
|
+
prepareView(viewId: string, view: WebContentsView, bounds: layout.Bounds): void;
|
|
54
|
+
/** Detach and close one concrete view instance through the native-tree owner. */
|
|
55
|
+
destroyView(viewId: string, view: WebContentsView | null): void;
|
|
66
56
|
setBaseDesired(viewId: string, desired: DesiredView<DevtoolsExtra>): void;
|
|
67
57
|
deleteBaseDesired(viewId: string): void;
|
|
68
58
|
setOverlayDesired(viewId: string, desired: DesiredView<DevtoolsExtra>): void;
|
|
69
59
|
deleteOverlayDesired(viewId: string): void;
|
|
70
60
|
hasOverlayDesired(viewId: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Hand out a fresh generation seed for a renderer bootstrap (see
|
|
63
|
+
* renderer-placement-generation.ts). Strictly exceeds both the current
|
|
64
|
+
* high-water mark (`rendererGeneration`, which a full renderer reload does
|
|
65
|
+
* NOT reset — this reconciler lives in the long-lived main process) and
|
|
66
|
+
* every previously allocated seed, so a reload that races ahead of its own
|
|
67
|
+
* previous session's accepted snapshots can never be handed a value that
|
|
68
|
+
* `setPlacementSnapshot` would reject as stale.
|
|
69
|
+
*/
|
|
70
|
+
allocateGeneration(): number;
|
|
71
71
|
}
|
|
72
72
|
export declare function createPlacementReconciler(ctx: ViewManagerContext): PlacementReconciler;
|
|
73
73
|
//# sourceMappingURL=placement-reconciler.d.ts.map
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { reconcile, createInitialState } from '@dimina-kit/electron-deck/layout';
|
|
2
2
|
import { applyViewOps } from './apply-view-ops.js';
|
|
3
|
+
import { createNativeViewTreeHost } from './native-view-tree.js';
|
|
3
4
|
export function createPlacementReconciler(ctx) {
|
|
4
5
|
let placementState = createInitialState();
|
|
5
6
|
let epochCounter = 0;
|
|
6
7
|
let rendererGeneration = 0;
|
|
8
|
+
let allocatedGeneration = 0;
|
|
9
|
+
const appliedActual = new Map();
|
|
7
10
|
const baseDesired = new Map();
|
|
8
11
|
const overlayDesired = new Map();
|
|
9
12
|
const slots = new Map();
|
|
13
|
+
// Sole owner of the main window's native child tree. Every attach, detach,
|
|
14
|
+
// reorder and hard destroy passes through this ledger-backed adapter.
|
|
15
|
+
const contentViewHost = createNativeViewTreeHost(ctx, slots);
|
|
10
16
|
function gateReadiness(v) {
|
|
11
17
|
const slot = slots.get(v.viewId);
|
|
12
18
|
if (slot?.gateHidden?.())
|
|
@@ -20,59 +26,67 @@ export function createPlacementReconciler(ctx) {
|
|
|
20
26
|
const slot = slots.get(viewId);
|
|
21
27
|
if (!slot)
|
|
22
28
|
return;
|
|
23
|
-
if (slot.beforeAttach?.())
|
|
24
|
-
return;
|
|
25
29
|
const view = slot.ensureView ? slot.ensureView() : slot.getView();
|
|
26
30
|
if (!view)
|
|
27
31
|
return;
|
|
28
|
-
|
|
29
|
-
|
|
32
|
+
if (!contentViewHost.addChildView({ id: viewId }))
|
|
33
|
+
return;
|
|
34
|
+
const previous = appliedActual.get(viewId);
|
|
35
|
+
appliedActual.set(viewId, {
|
|
36
|
+
attached: true,
|
|
37
|
+
visible: true,
|
|
38
|
+
bounds: previous?.bounds,
|
|
39
|
+
extra: previous?.extra,
|
|
40
|
+
});
|
|
30
41
|
},
|
|
31
42
|
detach(viewId) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
ctx.windows.mainWindow.contentView.removeChildView(view);
|
|
37
|
-
}
|
|
38
|
-
catch { /* already removed */ }
|
|
39
|
-
}
|
|
40
|
-
slot?.setAdded?.(false);
|
|
43
|
+
if (!contentViewHost.removeChildView({ id: viewId }))
|
|
44
|
+
return;
|
|
45
|
+
appliedActual.delete(viewId);
|
|
41
46
|
},
|
|
42
47
|
setBounds(viewId, bounds, extra) {
|
|
43
48
|
const slot = slots.get(viewId);
|
|
44
49
|
const view = slot?.getView() ?? null;
|
|
45
50
|
if (!view || view.webContents.isDestroyed())
|
|
46
51
|
return;
|
|
47
|
-
|
|
48
|
-
slot
|
|
52
|
+
try {
|
|
53
|
+
if (slot?.applyBounds)
|
|
54
|
+
slot.applyBounds(view, bounds, extra);
|
|
55
|
+
else
|
|
56
|
+
view.setBounds(bounds);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
49
59
|
return;
|
|
50
60
|
}
|
|
51
|
-
|
|
61
|
+
const previous = appliedActual.get(viewId);
|
|
62
|
+
appliedActual.set(viewId, {
|
|
63
|
+
attached: previous?.attached ?? false,
|
|
64
|
+
visible: previous?.visible ?? false,
|
|
65
|
+
bounds,
|
|
66
|
+
extra,
|
|
67
|
+
});
|
|
52
68
|
},
|
|
53
69
|
setVisible(viewId, visible) {
|
|
54
70
|
const view = slots.get(viewId)?.getView() ?? null;
|
|
55
|
-
if (!view)
|
|
71
|
+
if (!view || view.webContents.isDestroyed())
|
|
56
72
|
return;
|
|
57
73
|
try {
|
|
58
74
|
view.setVisible(visible);
|
|
59
75
|
}
|
|
60
|
-
catch {
|
|
76
|
+
catch {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const previous = appliedActual.get(viewId);
|
|
80
|
+
if (!previous)
|
|
81
|
+
return;
|
|
82
|
+
appliedActual.set(viewId, { ...previous, visible });
|
|
61
83
|
},
|
|
62
84
|
reorder(order) {
|
|
63
85
|
// A single attached view is already in place — nothing to reorder.
|
|
64
86
|
if (order.length <= 1 || ctx.windows.mainWindow.isDestroyed())
|
|
65
87
|
return;
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
const view = slots.get(viewId)?.getView() ?? null;
|
|
69
|
-
if (view) {
|
|
70
|
-
try {
|
|
71
|
-
cv.addChildView(view);
|
|
72
|
-
}
|
|
73
|
-
catch { /* already attached */ }
|
|
74
|
-
}
|
|
75
|
-
}
|
|
88
|
+
for (const viewId of order)
|
|
89
|
+
contentViewHost.addChildView({ id: viewId });
|
|
76
90
|
},
|
|
77
91
|
};
|
|
78
92
|
// Create the lazily-built views (host-toolbar, workbench) BEFORE reconcile so
|
|
@@ -83,6 +97,9 @@ export function createPlacementReconciler(ctx) {
|
|
|
83
97
|
slot.ensureLazy?.(baseDesired.get(viewId));
|
|
84
98
|
}
|
|
85
99
|
}
|
|
100
|
+
function cloneAppliedActual() {
|
|
101
|
+
return new Map([...appliedActual].map(([viewId, actual]) => [viewId, { ...actual }]));
|
|
102
|
+
}
|
|
86
103
|
function reconcileNow() {
|
|
87
104
|
ensureLazyViews();
|
|
88
105
|
const views = [];
|
|
@@ -90,6 +107,7 @@ export function createPlacementReconciler(ctx) {
|
|
|
90
107
|
views.push(gateReadiness(v));
|
|
91
108
|
for (const v of overlayDesired.values())
|
|
92
109
|
views.push(v);
|
|
110
|
+
placementState = { ...placementState, actual: cloneAppliedActual() };
|
|
93
111
|
const result = reconcile(placementState, {
|
|
94
112
|
generation: rendererGeneration,
|
|
95
113
|
epoch: ++epochCounter,
|
|
@@ -97,8 +115,33 @@ export function createPlacementReconciler(ctx) {
|
|
|
97
115
|
});
|
|
98
116
|
placementState = result.state;
|
|
99
117
|
applyViewOps(result.ops, viewTarget);
|
|
118
|
+
// The planner's next state is optimistic. Keep only desired/epoch metadata;
|
|
119
|
+
// appliedActual is updated by successful native effects above.
|
|
120
|
+
placementState = { ...placementState, actual: cloneAppliedActual() };
|
|
100
121
|
}
|
|
101
122
|
function setPlacementSnapshot(snapshot) {
|
|
123
|
+
// Hard reject a snapshot from BEHIND the current high-water mark — a
|
|
124
|
+
// complete no-op, touching neither `rendererGeneration` nor
|
|
125
|
+
// `baseDesired`. The renderer hands out one shared, strictly monotonic
|
|
126
|
+
// sequence across every screen (see renderer-placement-generation.ts),
|
|
127
|
+
// so under normal operation a lower generation can only be a LATE
|
|
128
|
+
// arrival from an already-superseded source (e.g. a dead screen's
|
|
129
|
+
// delayed `dispose()` empty-snapshot flush racing a successor screen's
|
|
130
|
+
// mount). The previous version of this guard clamped
|
|
131
|
+
// `rendererGeneration` to never regress but still unconditionally
|
|
132
|
+
// applied the stale snapshot's CONTENT into `baseDesired` under the
|
|
133
|
+
// clamped (i.e. current) generation number — which defeated the
|
|
134
|
+
// reconcile core's own generation-regression guard
|
|
135
|
+
// (placement-reconcile.ts: `snapshot.generation < prev.generation`) by
|
|
136
|
+
// never letting it see the snapshot's real, lower generation. That let a
|
|
137
|
+
// dead screen's stale/empty view list silently overwrite a currently
|
|
138
|
+
// active screen's real views. Dropping it here, before it ever reaches
|
|
139
|
+
// `baseDesired`, is what actually gives the stale snapshot zero side
|
|
140
|
+
// effects.
|
|
141
|
+
if (snapshot.generation < rendererGeneration) {
|
|
142
|
+
console.warn(`[placement-reconciler] snapshot generation ${snapshot.generation} is behind the current ${rendererGeneration}; dropping without applying its content`);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
102
145
|
rendererGeneration = snapshot.generation;
|
|
103
146
|
baseDesired.clear();
|
|
104
147
|
for (const v of snapshot.views)
|
|
@@ -109,12 +152,31 @@ export function createPlacementReconciler(ctx) {
|
|
|
109
152
|
registerView: (viewId, slot) => { slots.set(viewId, slot); },
|
|
110
153
|
reconcileNow,
|
|
111
154
|
setPlacementSnapshot,
|
|
112
|
-
|
|
155
|
+
prepareView: (viewId, view, bounds) => {
|
|
156
|
+
if (slots.get(viewId)?.getView() !== view || view.webContents.isDestroyed())
|
|
157
|
+
return;
|
|
158
|
+
try {
|
|
159
|
+
view.setBounds(bounds);
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
appliedActual.set(viewId, { attached: false, visible: false, bounds });
|
|
165
|
+
},
|
|
166
|
+
destroyView: (viewId, view) => {
|
|
167
|
+
contentViewHost.destroyView(viewId, view);
|
|
168
|
+
appliedActual.delete(viewId);
|
|
169
|
+
placementState.actual.delete(viewId);
|
|
170
|
+
},
|
|
113
171
|
setBaseDesired: (viewId, desired) => { baseDesired.set(viewId, desired); },
|
|
114
172
|
deleteBaseDesired: (viewId) => { baseDesired.delete(viewId); },
|
|
115
173
|
setOverlayDesired: (viewId, desired) => { overlayDesired.set(viewId, desired); },
|
|
116
174
|
deleteOverlayDesired: (viewId) => { overlayDesired.delete(viewId); },
|
|
117
175
|
hasOverlayDesired: (viewId) => overlayDesired.has(viewId),
|
|
176
|
+
allocateGeneration: () => {
|
|
177
|
+
allocatedGeneration = Math.max(allocatedGeneration, rendererGeneration) + 1;
|
|
178
|
+
return allocatedGeneration;
|
|
179
|
+
},
|
|
118
180
|
};
|
|
119
181
|
}
|
|
120
182
|
//# sourceMappingURL=placement-reconciler.js.map
|