diff --git a/Cargo.toml b/Cargo.toml index d1ac279a..dd175f42 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,7 @@ parking_lot = "0.12.5" postcard = { version = "1.0.8", features = ["use-std"] } replace_with = "0.1.8" serde = { version = "1.0.164", features = ["derive"] } -serde_json = "1.0.116" +serde_json = "1.0.149" serde_tuple = "1.1.2" smallbox = "0.8.8" static_assertions = "1.1.0" diff --git a/applications/Cargo.toml b/applications/Cargo.toml index 91422207..bf2f917c 100644 --- a/applications/Cargo.toml +++ b/applications/Cargo.toml @@ -15,6 +15,7 @@ massive-input.workspace = true anyhow.workspace = true derive_more.workspace = true log.workspace = true +serde_json.workspace = true tokio.workspace = true uuid.workspace = true # Architecture: We should get rid of the winit dependency here. Current ViewEvent depends on it, diff --git a/applications/src/instance_context.rs b/applications/src/instance_context.rs index 9aa98681..8bc9aaa7 100644 --- a/applications/src/instance_context.rs +++ b/applications/src/instance_context.rs @@ -11,14 +11,14 @@ use massive_renderer::FontManager; use massive_util::{CoalescingKey, CoalescingReceiver}; use crate::{ - InstanceEnvironment, InstanceId, Scene, ViewEvent, ViewExtent, ViewId, + InstanceEnvironment, InstanceId, InstanceParameters, Scene, ViewEvent, ViewExtent, ViewId, view::{ViewCommand, ViewCreationInfo}, view_builder::ViewBuilder, }; -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum CreationMode { - New, + New(InstanceParameters), Restore, } @@ -57,8 +57,15 @@ impl InstanceContext { self.id } - pub fn creation_mode(&self) -> CreationMode { - self.creation_mode + pub fn creation_mode(&self) -> &CreationMode { + &self.creation_mode + } + + pub fn parameters(&self) -> Option<&InstanceParameters> { + match &self.creation_mode { + CreationMode::New(map) => Some(map), + CreationMode::Restore => None, + } } pub fn primary_monitor_scale_factor(&self) -> f64 { diff --git a/applications/src/instance_environment.rs b/applications/src/instance_environment.rs index 055b50e7..9adce5d3 100644 --- a/applications/src/instance_environment.rs +++ b/applications/src/instance_environment.rs @@ -1,4 +1,5 @@ use massive_renderer::FontManager; +use serde_json::{Map, Value}; use tokio::sync::mpsc::UnboundedSender; use crate::{InstanceCommand, InstanceId}; @@ -9,8 +10,11 @@ pub struct InstanceEnvironment { // Robustness: This might change on runtime. pub(crate) primary_monitor_scale_factor: f64, pub(crate) font_manager: FontManager, + pub(crate) parameters: Map, } +pub type InstanceParameters = Map; + impl InstanceEnvironment { pub fn new( requests_tx: UnboundedSender<(InstanceId, InstanceCommand)>, @@ -21,6 +25,12 @@ impl InstanceEnvironment { command_sender: requests_tx, primary_monitor_scale_factor, font_manager, + parameters: Default::default(), } } + + pub fn with_parameters(mut self, parameters: InstanceParameters) -> Self { + self.parameters = parameters; + self + } } diff --git a/desktop/Cargo.toml b/desktop/Cargo.toml index 714c3386..35a47c88 100644 --- a/desktop/Cargo.toml +++ b/desktop/Cargo.toml @@ -23,6 +23,7 @@ derive_more.workspace = true euclid.workspace = true futures.workspace = true log.workspace = true +serde_json.workspace = true serde.workspace = true tokio = { workspace = true, features = ["time"] } toml.workspace = true diff --git a/desktop/src/desktop.rs b/desktop/src/desktop.rs index fc8c5ab6..bf2b95f5 100644 --- a/desktop/src/desktop.rs +++ b/desktop/src/desktop.rs @@ -6,8 +6,8 @@ use tokio::sync::mpsc::{UnboundedReceiver, unbounded_channel}; use uuid::Uuid; use massive_applications::{ - CreationMode, InstanceCommand, InstanceEnvironment, InstanceEvent, InstanceId, ViewCommand, - ViewEvent, ViewId, ViewRole, + CreationMode, InstanceCommand, InstanceEnvironment, InstanceEvent, InstanceId, + InstanceParameters, ViewCommand, ViewEvent, ViewId, ViewRole, }; use massive_input::{EventManager, ExternalEvent}; use massive_renderer::RenderPacing; @@ -72,7 +72,10 @@ impl Desktop { .get_named(&env.primary_application) .expect("No primary application"); - instance_manager.spawn(primary_application, CreationMode::New)?; + instance_manager.spawn( + primary_application, + CreationMode::New(InstanceParameters::new()), + )?; // First wait for the initial view that's being created. @@ -201,6 +204,7 @@ impl Desktop { } UserIntent::StartInstance { originating_instance, + parameters, } => { // Feature: Support starting non-primary applications. let application = self @@ -211,7 +215,7 @@ impl Desktop { let instance = self .instance_manager - .spawn(application, CreationMode::New)?; + .spawn(application, CreationMode::New(parameters))?; // Simplify: Use the currently focused instance for determining the originating one. let band_location = self diff --git a/desktop/src/desktop_interaction.rs b/desktop/src/desktop_interaction.rs index b014bd86..e81198ce 100644 --- a/desktop/src/desktop_interaction.rs +++ b/desktop/src/desktop_interaction.rs @@ -5,7 +5,7 @@ use winit::{ }; use massive_animation::{Animated, Interpolation}; -use massive_applications::{InstanceId, ViewEvent, ViewRole}; +use massive_applications::{InstanceId, InstanceParameters, ViewEvent, ViewRole}; use massive_geometry::PixelCamera; use massive_input::Event; use massive_renderer::RenderGeometry; @@ -31,6 +31,7 @@ pub enum UserIntent { // // Idea: What about looking for which presenter has the focus currently? originating_instance: Option, + parameters: InstanceParameters, }, StopInstance { instance: InstanceId, @@ -175,6 +176,7 @@ impl DesktopInteraction { Key::Character(c) if c.as_str() == "t" => { return Ok(UserIntent::StartInstance { originating_instance: Some(instance), + parameters: Default::default(), }); } Key::Character(c) if c.as_str() == "w" => { diff --git a/desktop/src/instance_manager.rs b/desktop/src/instance_manager.rs index 17584c86..f5158342 100644 --- a/desktop/src/instance_manager.rs +++ b/desktop/src/instance_manager.rs @@ -29,8 +29,6 @@ pub struct InstanceManager { #[derive(Debug)] struct RunningInstance { application_name: String, - #[allow(dead_code)] - creation_mode: CreationMode, events_tx: UnboundedSender, views: HashMap, } @@ -107,7 +105,6 @@ impl InstanceManager { instance_id, RunningInstance { application_name: application.name.clone(), - creation_mode, events_tx, views: HashMap::new(), }, diff --git a/desktop/src/lib.rs b/desktop/src/lib.rs index de7c6f11..9aa2b93f 100644 --- a/desktop/src/lib.rs +++ b/desktop/src/lib.rs @@ -19,6 +19,7 @@ pub use desktop_interaction::*; pub use desktop_presenter::DesktopPresenter; pub use event_router::{EventRouter, EventTransition, HitTester}; + // A layout helper. // Robustness: Can't we implement ToPixels somewhere? diff --git a/desktop/src/projects/configuration/toml_reader.rs b/desktop/src/projects/configuration/toml_reader.rs index d3ada21a..aff448dd 100644 --- a/desktop/src/projects/configuration/toml_reader.rs +++ b/desktop/src/projects/configuration/toml_reader.rs @@ -3,11 +3,10 @@ use std::collections::HashMap; use anyhow::Result; use indexmap::IndexMap; use serde::Deserialize; +use serde_json::Map; use toml::Value; -use super::types::{ - GroupContents, LaunchGroup, LaunchProfile, LayoutDirection, Parameter, Parameters, ScopedTag, -}; +use super::types::{GroupContents, LaunchGroup, LaunchProfile, LayoutDirection, ScopedTag}; /// Intermediate representation for deserializing TOML configuration files. #[derive(Debug, Deserialize)] @@ -71,23 +70,18 @@ fn build_launch_profile( groups: &[String], ) -> Result { let mut tags = Vec::new(); - let mut params = Vec::new(); + let mut params = Map::new(); for (key, value) in section { - let value = toml_value_to_string(&value)?; - if groups.contains(&key) { + let value = toml_value_to_string(&value)?; tags.push(ScopedTag::new(key, value)); } else { - params.push(Parameter::new(key, value)); + params.insert(key, serde_json::to_value(&value)?); } } - Ok(LaunchProfile { - name, - params: Parameters(params), - tags, - }) + Ok(LaunchProfile { name, params, tags }) } /// Build a cross-product hierarchy of groups at the given depth level. @@ -224,7 +218,7 @@ datacenter = "ber" assert_eq!(app_ref.name, "host-1"); assert_eq!(app_ref.params.len(), 1); - assert_eq!(app_ref.params[0].name, "command"); + assert!(app_ref.params.contains_key("command")); assert_eq!(app_ref.tags.len(), 2); assert!(app_ref.tags.iter().any(|t| t.scope == "datacenter")); assert!(app_ref.tags.iter().any(|t| t.scope == "type")); @@ -323,14 +317,14 @@ datacenter = "ber" } fn app(name: &str, params: &[(&str, &str)], tags: &[(&str, &str)]) -> LaunchProfile { + let mut param_map = Map::new(); + for (k, v) in params { + param_map.insert(k.to_string(), serde_json::Value::String(v.to_string())); + } + LaunchProfile { name: name.to_string(), - params: Parameters( - params - .iter() - .map(|(k, v)| Parameter::new(k.to_string(), v.to_string())) - .collect(), - ), + params: param_map, tags: tags .iter() .map(|(scope, tag)| ScopedTag::new(scope.to_string(), tag.to_string())) diff --git a/desktop/src/projects/configuration/types.rs b/desktop/src/projects/configuration/types.rs index 2d020756..ba63646b 100644 --- a/desktop/src/projects/configuration/types.rs +++ b/desktop/src/projects/configuration/types.rs @@ -1,4 +1,5 @@ -use derive_more::Deref; +use serde_json::{Map, Value}; + use massive_layout::LayoutAxis; #[derive(Debug)] @@ -34,7 +35,7 @@ pub enum GroupContents { #[derive(Debug, Clone)] pub struct LaunchProfile { pub name: String, - pub params: Parameters, + pub params: Map, pub tags: Vec, } @@ -52,17 +53,3 @@ impl ScopedTag { } } } - -#[derive(Debug, Deref, Clone, Default)] -pub struct Parameters(pub Vec); - -#[derive(Debug, Clone)] -pub struct Parameter { - pub name: String, - pub value: String, -} -impl Parameter { - pub fn new(name: String, value: String) -> Self { - Self { name, value } - } -} diff --git a/desktop/src/projects/launcher_presenter.rs b/desktop/src/projects/launcher_presenter.rs index c3f9ac92..0943de71 100644 --- a/desktop/src/projects/launcher_presenter.rs +++ b/desktop/src/projects/launcher_presenter.rs @@ -148,6 +148,7 @@ impl LauncherPresenter { // Usability: Should pass this rect? return Ok(UserIntent::StartInstance { originating_instance: None, + parameters: self.profile.params.clone(), }); } ViewEvent::CursorEntered { .. } => { diff --git a/desktop/src/projects/mod.rs b/desktop/src/projects/mod.rs index 45e047c6..a1a78498 100644 --- a/desktop/src/projects/mod.rs +++ b/desktop/src/projects/mod.rs @@ -6,9 +6,7 @@ use log::warn; use crate::{ band_presenter::BandTarget, - projects::configuration::{ - GroupContents, LaunchProfile, LayoutDirection, Parameters, ScopedTag, - }, + projects::configuration::{GroupContents, LaunchProfile, LayoutDirection, ScopedTag}, }; mod configuration; @@ -72,7 +70,7 @@ impl Default for ProjectConfiguration { content: GroupContents::Profiles( [LaunchProfile { name: DEFAULT_PROFILE.into(), - params: Parameters::default(), + params: Default::default(), tags: Vec::new(), }] .into(),