mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 14:18:04 +08:00
Replace globals with editor environment (#3656)
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
@@ -16,7 +16,6 @@
|
||||
import { createNodeGraphState } from "@graphite/state-providers/node-graph";
|
||||
import { createPortfolioState } from "@graphite/state-providers/portfolio";
|
||||
import { createTooltipState } from "@graphite/state-providers/tooltip";
|
||||
import { operatingSystem } from "@graphite/utility-functions/platform";
|
||||
|
||||
import MainWindow from "@graphite/components/window/MainWindow.svelte";
|
||||
|
||||
@@ -51,7 +50,7 @@
|
||||
|
||||
onMount(() => {
|
||||
// Initialize certain setup tasks required by the editor backend to be ready for the user now that the frontend is ready
|
||||
editor.handle.initAfterFrontendReady(operatingSystem());
|
||||
editor.handle.initAfterFrontendReady();
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
// import { panicProxy } from "@graphite/utility-functions/panic-proxy";
|
||||
import init, { setRandomSeed, wasmMemory, EditorHandle, receiveNativeMessage } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
|
||||
import { EditorHandle } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import init, { wasmMemory, receiveNativeMessage } from "@graphite/../wasm/pkg/graphite_wasm";
|
||||
import { type JsMessageType } from "@graphite/messages";
|
||||
import { createSubscriptionRouter, type SubscriptionRouter } from "@graphite/subscription-router";
|
||||
import { operatingSystem } from "@graphite/utility-functions/platform";
|
||||
|
||||
// TODO: Remove `raw`, split out `subscriptions`, and unwrap the remaining `handle` so `EditorHandle` can replace `Editor` and then it can also be renamed to `Editor` to fully remove `EditorHandle`.
|
||||
export type Editor = {
|
||||
raw: WebAssembly.Memory;
|
||||
handle: EditorHandle;
|
||||
@@ -14,10 +18,10 @@ let wasmImport: WebAssembly.Memory | undefined;
|
||||
|
||||
// Should be called asynchronously before `createEditor()`.
|
||||
export async function initWasm() {
|
||||
// Skip if the WASM module is already initialized
|
||||
// Skip if the Wasm module is already initialized
|
||||
if (wasmImport !== undefined) return;
|
||||
|
||||
// Import the WASM module JS bindings and wrap them in the panic proxy
|
||||
// Import the Wasm module JS bindings and wrap them in the panic proxy
|
||||
const wasm = await init();
|
||||
for (const [name, f] of Object.entries(wasm)) {
|
||||
if (name.startsWith("__node_registry")) f();
|
||||
@@ -28,28 +32,27 @@ export async function initWasm() {
|
||||
(window as any).imageCanvases = {};
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(window as any).receiveNativeMessage = receiveNativeMessage;
|
||||
|
||||
// Provide a random starter seed which must occur after initializing the WASM module, since WASM can't generate its own random numbers
|
||||
const randomSeedFloat = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
||||
const randomSeed = BigInt(randomSeedFloat);
|
||||
setRandomSeed(randomSeed);
|
||||
}
|
||||
|
||||
// Should be called after running `initWasm()` and its promise resolving.
|
||||
export function createEditor(): Editor {
|
||||
// Raw: object containing several callable functions from `editor_api.rs` defined directly on the WASM module, not the `EditorHandle` struct (generated by wasm-bindgen)
|
||||
if (!wasmImport) throw new Error("Editor WASM backend was not initialized at application startup");
|
||||
// Raw: object containing several callable functions from `editor_api.rs` defined directly on the Wasm module, not the `EditorHandle` struct (generated by wasm-bindgen)
|
||||
if (!wasmImport) throw new Error("Editor Wasm backend was not initialized at application startup");
|
||||
const raw: WebAssembly.Memory = wasmImport;
|
||||
|
||||
// Provide a random starter seed which must occur after initializing the Wasm module, since Wasm can't generate its own random numbers
|
||||
const randomSeedFloat = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
|
||||
const randomSeed = BigInt(randomSeedFloat);
|
||||
|
||||
// Handle: object containing many functions from `editor_api.rs` that are part of the `EditorHandle` struct (generated by wasm-bindgen)
|
||||
const handle: EditorHandle = new EditorHandle((messageType: JsMessageType, messageData: Record<string, unknown>) => {
|
||||
// This callback is called by WASM when a FrontendMessage is received from the WASM wrapper `EditorHandle`
|
||||
const handle = EditorHandle.create(operatingSystem(), randomSeed, (messageType: JsMessageType, messageData: Record<string, unknown>) => {
|
||||
// This callback is called by Wasm when a FrontendMessage is received from the Wasm wrapper `EditorHandle`
|
||||
// We pass along the first two arguments then add our own `raw` and `handle` context for the last two arguments
|
||||
subscriptions.handleJsMessage(messageType, messageData, raw, handle);
|
||||
});
|
||||
|
||||
// Subscriptions: allows subscribing to messages in JS that are sent from the WASM backend
|
||||
const subscriptions: SubscriptionRouter = createSubscriptionRouter();
|
||||
// Subscriptions: allows subscribing to messages in JS that are sent from the Wasm backend
|
||||
const subscriptions = createSubscriptionRouter();
|
||||
|
||||
// Check if the URL hash fragment has any demo artwork to be loaded
|
||||
(async () => {
|
||||
|
||||
@@ -40,7 +40,7 @@ export function githubUrl(panicDetails: string): string {
|
||||
Provide any further information or context that you think would be helpful in fixing the issue. Screenshots or video can be linked or attached to this issue.
|
||||
|
||||
**Browser and OS**
|
||||
${browserVersion()}, ${operatingSystem().replace("Unknown", "YOUR OPERATING SYSTEM")}
|
||||
${browserVersion()}, ${operatingSystem()}
|
||||
|
||||
**Stack Trace**
|
||||
Copied from the crash dialog in the Graphite editor:
|
||||
|
||||
@@ -25,18 +25,17 @@ export function browserVersion(): string {
|
||||
return `${match[0]} ${match[1]}`;
|
||||
}
|
||||
|
||||
export type OperatingSystem = "Windows" | "Mac" | "Linux" | "Unknown";
|
||||
export type OperatingSystem = "Windows" | "Mac" | "Linux";
|
||||
|
||||
export function operatingSystem(): OperatingSystem {
|
||||
const osTable: Record<string, OperatingSystem> = {
|
||||
Windows: "Windows",
|
||||
Mac: "Mac",
|
||||
Linux: "Linux",
|
||||
Unknown: "Unknown",
|
||||
};
|
||||
|
||||
const userAgentOS = Object.keys(osTable).find((key) => window.navigator.userAgent.includes(key));
|
||||
return osTable[userAgentOS || "Unknown"];
|
||||
return osTable[userAgentOS || "Windows"];
|
||||
}
|
||||
|
||||
export function isDesktop(): boolean {
|
||||
|
||||
@@ -12,7 +12,7 @@ use editor::messages::input_mapper::utility_types::input_keyboard::ModifierKeys;
|
||||
use editor::messages::input_mapper::utility_types::input_mouse::{EditorMouseState, ScrollDelta};
|
||||
use editor::messages::portfolio::document::utility_types::document_metadata::LayerNodeIdentifier;
|
||||
use editor::messages::portfolio::document::utility_types::network_interface::ImportOrExport;
|
||||
use editor::messages::portfolio::utility_types::{FontCatalog, FontCatalogFamily, Platform};
|
||||
use editor::messages::portfolio::utility_types::{FontCatalog, FontCatalogFamily};
|
||||
use editor::messages::prelude::*;
|
||||
use editor::messages::tool::tool_messages::tool_prelude::WidgetId;
|
||||
use graph_craft::document::NodeId;
|
||||
@@ -31,7 +31,7 @@ use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, ImageData, window};
|
||||
#[cfg(not(feature = "native"))]
|
||||
use crate::EDITOR;
|
||||
#[cfg(not(feature = "native"))]
|
||||
use editor::application::Editor;
|
||||
use editor::application::{Editor, Environment, Host, Platform};
|
||||
|
||||
static IMAGE_DATA_HASH: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
@@ -43,14 +43,7 @@ fn calculate_hash<T: std::hash::Hash>(t: &T) -> u64 {
|
||||
hasher.finish()
|
||||
}
|
||||
|
||||
/// Set the random seed used by the editor by calling this from JS upon initialization.
|
||||
/// This is necessary because WASM doesn't have a random number generator.
|
||||
#[wasm_bindgen(js_name = setRandomSeed)]
|
||||
pub fn set_random_seed(seed: u64) {
|
||||
editor::application::set_uuid_seed(seed);
|
||||
}
|
||||
|
||||
/// Provides a handle to access the raw WASM memory.
|
||||
/// Provides a handle to access the raw Wasm memory.
|
||||
#[wasm_bindgen(js_name = wasmMemory)]
|
||||
pub fn wasm_memory() -> JsValue {
|
||||
wasm_bindgen::memory()
|
||||
@@ -89,9 +82,20 @@ impl EditorHandle {
|
||||
#[wasm_bindgen]
|
||||
impl EditorHandle {
|
||||
#[cfg(not(feature = "native"))]
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(frontend_message_handler_callback: js_sys::Function) -> Self {
|
||||
let editor = Editor::new();
|
||||
pub fn create(platform: String, uuid_random_seed: u64, frontend_message_handler_callback: js_sys::Function) -> EditorHandle {
|
||||
let editor = Editor::new(
|
||||
Environment {
|
||||
platform: Platform::Web,
|
||||
host: match platform.as_str() {
|
||||
"Linux" => Host::Linux,
|
||||
"Mac" => Host::Mac,
|
||||
"Windows" => Host::Windows,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
},
|
||||
uuid_random_seed,
|
||||
);
|
||||
|
||||
let editor_handle = EditorHandle { frontend_message_handler_callback };
|
||||
if EDITOR.with(|handle| handle.lock().ok().map(|mut guard| *guard = Some(editor))).is_none() {
|
||||
log::error!("Attempted to initialize the editor more than once");
|
||||
@@ -103,8 +107,7 @@ impl EditorHandle {
|
||||
}
|
||||
|
||||
#[cfg(feature = "native")]
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(frontend_message_handler_callback: js_sys::Function) -> Self {
|
||||
pub fn create(_platform: String, _uuid_random_seed: u64, frontend_message_handler_callback: js_sys::Function) -> EditorHandle {
|
||||
let editor_handle = EditorHandle { frontend_message_handler_callback };
|
||||
if EDITOR_HANDLE.with(|handle| handle.lock().ok().map(|mut guard| *guard = Some(editor_handle.clone()))).is_none() {
|
||||
log::error!("Attempted to initialize the editor handle more than once");
|
||||
@@ -184,18 +187,10 @@ impl EditorHandle {
|
||||
// ========================================================================
|
||||
|
||||
#[wasm_bindgen(js_name = initAfterFrontendReady)]
|
||||
pub fn init_after_frontend_ready(&self, platform: String) {
|
||||
pub fn init_after_frontend_ready(&self) {
|
||||
#[cfg(feature = "native")]
|
||||
crate::native_communcation::initialize_native_communication();
|
||||
|
||||
// Send initialization messages
|
||||
let platform = match platform.as_str() {
|
||||
"Windows" => Platform::Windows,
|
||||
"Mac" => Platform::Mac,
|
||||
"Linux" => Platform::Linux,
|
||||
_ => Platform::Unknown,
|
||||
};
|
||||
self.dispatch(GlobalsMessage::SetPlatform { platform });
|
||||
self.dispatch(PortfolioMessage::Init);
|
||||
|
||||
// Poll node graph evaluation on `requestAnimationFrame`
|
||||
|
||||
Reference in New Issue
Block a user