diff --git a/extensions/core/src/bluetooth/bluez.rs b/extensions/core/src/bluetooth/bluez.rs index 2946efda..9cab950d 100644 --- a/extensions/core/src/bluetooth/bluez.rs +++ b/extensions/core/src/bluetooth/bluez.rs @@ -10,7 +10,7 @@ use std::{ use adapter::BluetoothAdapter; use device::BluetoothDevice; use futures_util::stream::StreamExt; -use godot::{obj::WithBaseField, prelude::*}; +use godot::{classes::Engine, obj::WithBaseField, prelude::*}; use zbus::fdo::ObjectManagerProxy; use zbus::{fdo::ManagedObjects, names::BusName}; @@ -221,10 +221,23 @@ impl BluezInstance { impl IResource for BluezInstance { /// Called upon object initialization in the engine fn init(base: Base) -> Self { - log::info!("Initializing Bluez instance"); + log::debug!("Initializing Bluez instance"); // Create a channel to communicate with the service let (tx, rx) = channel(); + let conn = get_dbus_system_blocking().ok(); + + // Don't run in the editor + let engine = Engine::singleton(); + if engine.is_editor_hint() { + return Self { + base, + rx, + conn, + adapters: Default::default(), + devices: Default::default(), + }; + } // Spawn a task using the shared tokio runtime to listen for signals RUNTIME.spawn(async move { @@ -234,7 +247,6 @@ impl IResource for BluezInstance { }); // Create a new Bluez instance - let conn = get_dbus_system_blocking().ok(); let mut instance = Self { base, rx, @@ -276,7 +288,7 @@ impl IResource for BluezInstance { /// Runs Bluez tasks in Tokio to listen for DBus signals and send them /// over the given channel so they can be processed during each engine frame. async fn run(tx: Sender) -> Result<(), RunError> { - log::info!("Spawning Bluez tasks"); + log::debug!("Spawning Bluez tasks"); // Establish a connection to the system bus let conn = get_dbus_system().await?; diff --git a/extensions/core/src/bluetooth/bluez/adapter.rs b/extensions/core/src/bluetooth/bluez/adapter.rs index 1db1e76a..87babced 100644 --- a/extensions/core/src/bluetooth/bluez/adapter.rs +++ b/extensions/core/src/bluetooth/bluez/adapter.rs @@ -110,7 +110,7 @@ impl BluetoothAdapter { /// Create a new [BluetoothAdapter] with the given DBus path pub fn from_path(path: GString) -> Gd { // Create a channel to communicate with the signals task - log::info!("BluetoothAdapter created with path: {path}"); + log::debug!("BluetoothAdapter created with path: {path}"); let (tx, rx) = channel(); let dbus_path = path.clone().into(); @@ -176,7 +176,7 @@ impl BluetoothAdapter { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists with path '{res_path}', loading that instead"); + log::debug!("Resource already exists with path '{res_path}', loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/bluetooth/bluez/device.rs b/extensions/core/src/bluetooth/bluez/device.rs index 1cf6c369..f317588a 100644 --- a/extensions/core/src/bluetooth/bluez/device.rs +++ b/extensions/core/src/bluetooth/bluez/device.rs @@ -105,7 +105,7 @@ impl BluetoothDevice { /// Create a new [BluetoothDevice] with the given DBus path pub fn from_path(path: GString) -> Gd { // Create a channel to communicate with the signals task - log::info!("BluetoothDevice created with path: {path}"); + log::debug!("BluetoothDevice created with path: {path}"); let (tx, rx) = channel(); let dbus_path = path.clone().into(); @@ -173,7 +173,7 @@ impl BluetoothDevice { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists with path '{res_path}', loading that instead"); + log::debug!("Resource already exists with path '{res_path}', loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/dbus.rs b/extensions/core/src/dbus.rs index ef4ef298..90075053 100644 --- a/extensions/core/src/dbus.rs +++ b/extensions/core/src/dbus.rs @@ -3,6 +3,7 @@ use zvariant::NoneValue; pub mod bluez; pub mod inputplumber; +pub mod networkmanager; pub mod powerstation; pub mod udisks2; pub mod upower; @@ -26,6 +27,68 @@ impl From for RunError { } } +/// Interface for converting DBus types -> Godot types +pub trait GodotVariant { + fn as_godot_variant(&self) -> Option; +} + +impl GodotVariant for zvariant::OwnedValue { + /// Convert the DBus variant type into a Godot variant type + fn as_godot_variant(&self) -> Option { + let value = zvariant::Value::try_from(self).ok()?; + value.as_godot_variant() + } +} + +impl<'a> GodotVariant for zvariant::Value<'a> { + /// Convert the DBus variant type into a Godot variant type + fn as_godot_variant(&self) -> Option { + match self { + zvariant::Value::U8(value) => Some(value.to_variant()), + zvariant::Value::Bool(value) => Some(value.to_variant()), + zvariant::Value::I16(value) => Some(value.to_variant()), + zvariant::Value::U16(value) => Some(value.to_variant()), + zvariant::Value::I32(value) => Some(value.to_variant()), + zvariant::Value::U32(value) => Some(value.to_variant()), + zvariant::Value::I64(value) => Some(value.to_variant()), + zvariant::Value::U64(value) => Some(value.to_variant()), + zvariant::Value::F64(value) => Some(value.to_variant()), + zvariant::Value::Str(value) => Some(value.to_string().to_variant()), + zvariant::Value::Signature(_) => None, + zvariant::Value::ObjectPath(value) => Some(value.to_string().to_variant()), + zvariant::Value::Value(_) => None, + zvariant::Value::Array(value) => { + let mut arr = array![]; + for item in value.iter() { + let Some(variant) = item.as_godot_variant() else { + continue; + }; + arr.push(&variant); + } + + Some(arr.to_variant()) + } + zvariant::Value::Dict(value) => { + let mut dict = Dictionary::new(); + for (key, val) in value.iter() { + let Some(key) = key.as_godot_variant() else { + continue; + }; + let Some(val) = val.as_godot_variant() else { + continue; + }; + dict.set(key, val); + } + + Some(dict.to_variant()) + } + zvariant::Value::Structure(_) => None, + zvariant::Value::Fd(_) => None, + } + } +} + +/// Interface for converting Godot types -> DBus types pub trait DBusVariant { fn as_zvariant(&self) -> Option; } @@ -55,44 +118,44 @@ impl DBusVariant for Variant { let value: String = value.into(); Some(zvariant::Value::new(value)) } - VariantType::VECTOR2 => todo!(), - VariantType::VECTOR2I => todo!(), - VariantType::RECT2 => todo!(), - VariantType::RECT2I => todo!(), - VariantType::VECTOR3 => todo!(), - VariantType::VECTOR3I => todo!(), - VariantType::TRANSFORM2D => todo!(), - VariantType::VECTOR4 => todo!(), - VariantType::VECTOR4I => todo!(), - VariantType::PLANE => todo!(), - VariantType::QUATERNION => todo!(), - VariantType::AABB => todo!(), - VariantType::BASIS => todo!(), - VariantType::TRANSFORM3D => todo!(), - VariantType::PROJECTION => todo!(), - VariantType::COLOR => todo!(), - VariantType::STRING_NAME => todo!(), - VariantType::NODE_PATH => todo!(), + VariantType::VECTOR2 => None, + VariantType::VECTOR2I => None, + VariantType::RECT2 => None, + VariantType::RECT2I => None, + VariantType::VECTOR3 => None, + VariantType::VECTOR3I => None, + VariantType::TRANSFORM2D => None, + VariantType::VECTOR4 => None, + VariantType::VECTOR4I => None, + VariantType::PLANE => None, + VariantType::QUATERNION => None, + VariantType::AABB => None, + VariantType::BASIS => None, + VariantType::TRANSFORM3D => None, + VariantType::PROJECTION => None, + VariantType::COLOR => None, + VariantType::STRING_NAME => None, + VariantType::NODE_PATH => None, VariantType::RID => { let value: i64 = self.to(); Some(zvariant::Value::new(value)) } - VariantType::OBJECT => todo!(), - VariantType::CALLABLE => todo!(), - VariantType::SIGNAL => todo!(), - VariantType::DICTIONARY => todo!(), - VariantType::ARRAY => todo!(), - VariantType::PACKED_BYTE_ARRAY => todo!(), - VariantType::PACKED_INT32_ARRAY => todo!(), - VariantType::PACKED_INT64_ARRAY => todo!(), - VariantType::PACKED_FLOAT32_ARRAY => todo!(), - VariantType::PACKED_FLOAT64_ARRAY => todo!(), - VariantType::PACKED_STRING_ARRAY => todo!(), - VariantType::PACKED_VECTOR2_ARRAY => todo!(), - VariantType::PACKED_VECTOR3_ARRAY => todo!(), - VariantType::PACKED_COLOR_ARRAY => todo!(), - VariantType::PACKED_VECTOR4_ARRAY => todo!(), - VariantType::MAX => todo!(), + VariantType::OBJECT => None, + VariantType::CALLABLE => None, + VariantType::SIGNAL => None, + VariantType::DICTIONARY => None, + VariantType::ARRAY => None, + VariantType::PACKED_BYTE_ARRAY => None, + VariantType::PACKED_INT32_ARRAY => None, + VariantType::PACKED_INT64_ARRAY => None, + VariantType::PACKED_FLOAT32_ARRAY => None, + VariantType::PACKED_FLOAT64_ARRAY => None, + VariantType::PACKED_STRING_ARRAY => None, + VariantType::PACKED_VECTOR2_ARRAY => None, + VariantType::PACKED_VECTOR3_ARRAY => None, + VariantType::PACKED_COLOR_ARRAY => None, + VariantType::PACKED_VECTOR4_ARRAY => None, + VariantType::MAX => None, // Unsupported conversion _ => None, diff --git a/extensions/core/src/disk/udisks2.rs b/extensions/core/src/disk/udisks2.rs index bd902ce6..f3c2263a 100644 --- a/extensions/core/src/disk/udisks2.rs +++ b/extensions/core/src/disk/udisks2.rs @@ -13,7 +13,7 @@ use block_device::BlockDevice; use drive_device::DriveDevice; use filesystem_device::FilesystemDevice; use futures_util::stream::StreamExt; -use godot::{obj::WithBaseField, prelude::*}; +use godot::{classes::Engine, obj::WithBaseField, prelude::*}; use partition_device::PartitionDevice; use zbus::fdo::{ManagedObjects, ObjectManagerProxy}; use zbus::names::BusName; @@ -174,17 +174,17 @@ impl UDisks2Instance { let partitions = block_device.bind().get_partitions(); if partitions.is_empty() { if !self.partition_devices.contains_key(dbus_path) { - log::info!( + log::debug!( "Adding {dbus_path} as unprotected device. It is not a partition_devices" ); unprotected_devices.push(block_device); continue; } - log::info!("Skipping {dbus_path}. It is a partition_device."); + log::debug!("Skipping {dbus_path}. It is a partition_device."); } else { for partition_device in partitions.iter_shared() { let Some(filesystem_device) = partition_device.bind().get_filesystem() else { - log::info!( + log::debug!( "Adding {dbus_path} as unprotected device. It does not have a FilesystemDevice" ); unprotected_devices.push(block_device); @@ -198,7 +198,7 @@ impl UDisks2Instance { } } } - log::info!( + log::debug!( "Adding {dbus_path} as unprotected device. It does not have any mounts in PROTECTED_MOUNTS" ); unprotected_devices.push(block_device); @@ -314,10 +314,25 @@ impl UDisks2Instance { impl IResource for UDisks2Instance { /// Called upon object initialization in the engine fn init(base: Base) -> Self { - log::info!("Initializing UDisks2 instance"); + log::debug!("Initializing UDisks2 instance"); // Create a channel to communicate with the service let (tx, rx) = channel(); + let conn = get_dbus_system_blocking().ok(); + + // Don't run in the editor + let engine = Engine::singleton(); + if engine.is_editor_hint() { + return Self { + base, + rx, + conn, + block_devices: Default::default(), + drive_devices: Default::default(), + partition_devices: Default::default(), + filesystem_devices: Default::default(), + }; + } // Spawn a task using the shared tokio runtime to listen for signals RUNTIME.spawn(async move { @@ -327,7 +342,6 @@ impl IResource for UDisks2Instance { }); // Create a new UDisks2 instance - let conn = get_dbus_system_blocking().ok(); let mut instance = Self { base, rx, @@ -382,7 +396,7 @@ impl IResource for UDisks2Instance { /// Runs UDisks2 tasks in Tokio to listen for DBus signals and send them /// over the given channel so they can be processed during each engine frame. async fn run(tx: Sender) -> Result<(), RunError> { - log::info!("Spawning UDisks2 tasks"); + log::debug!("Spawning UDisks2 tasks"); // Establish a connection to the system bus let conn = get_dbus_system().await?; diff --git a/extensions/core/src/disk/udisks2/block_device.rs b/extensions/core/src/disk/udisks2/block_device.rs index cbbcf346..d4d77d84 100644 --- a/extensions/core/src/disk/udisks2/block_device.rs +++ b/extensions/core/src/disk/udisks2/block_device.rs @@ -35,7 +35,7 @@ impl BlockDevice { /// Create a new [BlockDevice] with the given DBus path pub fn from_path(path: GString) -> Gd { // Create a channel to communicate with the signals task - log::info!("BlockDevice created with path: {path}"); + log::debug!("BlockDevice created with path: {path}"); Gd::from_init_fn(|base| { // Create a connection to DBus @@ -87,7 +87,7 @@ impl BlockDevice { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists with path '{res_path}', loading that instead"); + log::debug!("Resource already exists with path '{res_path}', loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/disk/udisks2/drive_device.rs b/extensions/core/src/disk/udisks2/drive_device.rs index f570c355..ad3a4045 100644 --- a/extensions/core/src/disk/udisks2/drive_device.rs +++ b/extensions/core/src/disk/udisks2/drive_device.rs @@ -39,7 +39,7 @@ impl DriveDevice { /// Create a new [DriveDevice] with the given DBus path pub fn from_path(path: GString) -> Gd { // Create a channel to communicate with the signals task - log::info!("DriveDevice created with path: {path}"); + log::debug!("DriveDevice created with path: {path}"); Gd::from_init_fn(|base| { // Create a connection to DBus @@ -77,7 +77,7 @@ impl DriveDevice { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists with path '{res_path}', loading that instead"); + log::debug!("Resource already exists with path '{res_path}', loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/disk/udisks2/filesystem_device.rs b/extensions/core/src/disk/udisks2/filesystem_device.rs index 33a9a483..69c99c68 100644 --- a/extensions/core/src/disk/udisks2/filesystem_device.rs +++ b/extensions/core/src/disk/udisks2/filesystem_device.rs @@ -26,7 +26,7 @@ impl FilesystemDevice { /// Create a new [FilesystemDevice] with the given DBus path pub fn from_path(path: GString) -> Gd { // Create a channel to communicate with the signals task - log::info!("FilesystemDevice created with path: {path}"); + log::debug!("FilesystemDevice created with path: {path}"); Gd::from_init_fn(|base| { // Create a connection to DBus @@ -64,7 +64,7 @@ impl FilesystemDevice { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists with path '{res_path}', loading that instead"); + log::debug!("Resource already exists with path '{res_path}', loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/disk/udisks2/partition_device.rs b/extensions/core/src/disk/udisks2/partition_device.rs index 3b440557..82ff2b94 100644 --- a/extensions/core/src/disk/udisks2/partition_device.rs +++ b/extensions/core/src/disk/udisks2/partition_device.rs @@ -43,7 +43,7 @@ impl PartitionDevice { /// Create a new [PartitionDevice] with the given DBus path pub fn from_path(path: GString) -> Gd { // Create a channel to communicate with the signals task - log::info!("PartitionDevice created with path: {path}"); + log::debug!("PartitionDevice created with path: {path}"); Gd::from_init_fn(|base| { // Create a connection to DBus @@ -109,7 +109,7 @@ impl PartitionDevice { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists with path '{res_path}', loading that instead"); + log::debug!("Resource already exists with path '{res_path}', loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/gamescope.rs b/extensions/core/src/gamescope.rs index 204e109c..92e2570e 100644 --- a/extensions/core/src/gamescope.rs +++ b/extensions/core/src/gamescope.rs @@ -6,7 +6,7 @@ use x11_client::GamescopeXWayland; use godot::prelude::*; -use godot::classes::Resource; +use godot::classes::{Engine, Resource}; #[derive(GodotClass)] #[class(base=Resource)] @@ -89,14 +89,26 @@ impl GamescopeInstance { impl IResource for GamescopeInstance { /// Called upon object initialization in the engine fn init(base: Base) -> Self { - log::info!("Initializing Gamescope instance"); + log::debug!("Initializing Gamescope instance"); + + // Don't run in the editor + let engine = Engine::singleton(); + if engine.is_editor_hint() { + return Self { + base, + xwaylands: Default::default(), + xwayland_primary: Default::default(), + xwayland_ogui: Default::default(), + xwayland_game: Default::default(), + }; + } // Discover any gamescope instances let result = gamescope_x11_client::discover_gamescope_displays(); let x11_displays = match result { Ok(displays) => displays, Err(e) => { - log::error!("Failed to get Gamescope displays: {e:?}"); + log::warn!("Failed to get Gamescope displays: {e:?}"); return Self { base, xwaylands: HashMap::new(), @@ -118,7 +130,7 @@ impl IResource for GamescopeInstance { // Create an XWayland instance for each discovered XWayland display for display in x11_displays { - log::info!("Discovered XWayland display: {display}"); + log::debug!("Discovered XWayland display: {display}"); let xwayland = GamescopeXWayland::new(display.as_str()); // Categorize the discovered displays diff --git a/extensions/core/src/input/inputplumber.rs b/extensions/core/src/input/inputplumber.rs index d59780d0..e0a570d2 100644 --- a/extensions/core/src/input/inputplumber.rs +++ b/extensions/core/src/input/inputplumber.rs @@ -13,7 +13,7 @@ use std::time::Duration; use composite_device::CompositeDevice; use godot::prelude::*; -use godot::classes::Resource; +use godot::classes::{Engine, Resource}; use zbus::fdo::ObjectManagerProxy; use zbus::names::BusName; @@ -340,7 +340,7 @@ impl InputPlumberInstance { match kind { ObjectType::Unknown => (), ObjectType::CompositeDevice => { - log::info!("CompositeDevice added: {path}"); + log::debug!("CompositeDevice added: {path}"); let device = CompositeDevice::new(path.as_str()); self.composite_devices.insert(path, device.clone()); self.base_mut() @@ -350,7 +350,7 @@ impl InputPlumberInstance { ObjectType::SourceHidRawDevice => (), ObjectType::SourceIioDevice => (), ObjectType::TargetDBusDevice => { - log::info!("DBusDevice added: {path}"); + log::debug!("DBusDevice added: {path}"); let device = DBusDevice::new(path.as_str()); self.dbus_devices.insert(path, device); } @@ -365,7 +365,7 @@ impl InputPlumberInstance { match kind { ObjectType::Unknown => (), ObjectType::CompositeDevice => { - log::info!("CompositeDevice device removed: {path}"); + log::debug!("CompositeDevice device removed: {path}"); self.composite_devices.remove(&path); self.base_mut().emit_signal( "composite_device_removed", @@ -376,7 +376,7 @@ impl InputPlumberInstance { ObjectType::SourceHidRawDevice => (), ObjectType::SourceIioDevice => (), ObjectType::TargetDBusDevice => { - log::info!("DBusDevice device removed: {path}"); + log::debug!("DBusDevice device removed: {path}"); self.dbus_devices.remove(&path); } ObjectType::TargetGamepadDevice => (), @@ -390,10 +390,26 @@ impl InputPlumberInstance { impl IResource for InputPlumberInstance { /// Called upon object initialization in the engine fn init(base: Base) -> Self { - log::info!("Initializing InputPlumber instance"); + log::debug!("Initializing InputPlumber instance"); // Create a channel to communicate with the service let (tx, rx) = channel(); + let conn = get_dbus_system_blocking().ok(); + + // Don't run in the editor + let engine = Engine::singleton(); + if engine.is_editor_hint() { + return Self { + base, + rx, + conn, + composite_devices: Default::default(), + dbus_devices: Default::default(), + intercept_mode: Default::default(), + intercept_triggers: Default::default(), + intercept_target: Default::default(), + }; + } // Spawn a task using the shared tokio runtime to listen for signals RUNTIME.spawn(async move { @@ -403,7 +419,6 @@ impl IResource for InputPlumberInstance { }); // Create a new InputPlumber instance - let conn = get_dbus_system_blocking().ok(); let mut instance = Self { base, rx, @@ -435,7 +450,7 @@ impl IResource for InputPlumberInstance { /// Runs InputPlumber tasks in Tokio to listen for DBus signals and send them /// over the given channel so they can be processed during each engine frame. async fn run(tx: Sender) -> Result<(), RunError> { - log::info!("Spawning inputplumber"); + log::debug!("Spawning inputplumber"); // Establish a connection to the system bus let conn = get_dbus_system().await?; diff --git a/extensions/core/src/input/inputplumber/composite_device.rs b/extensions/core/src/input/inputplumber/composite_device.rs index a89d4972..3f72eadf 100644 --- a/extensions/core/src/input/inputplumber/composite_device.rs +++ b/extensions/core/src/input/inputplumber/composite_device.rs @@ -103,7 +103,7 @@ impl CompositeDevice { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists with path '{res_path}', loading that instead"); + log::debug!("Resource already exists with path '{res_path}', loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/input/inputplumber/dbus_device.rs b/extensions/core/src/input/inputplumber/dbus_device.rs index c917414b..f7d56b95 100644 --- a/extensions/core/src/input/inputplumber/dbus_device.rs +++ b/extensions/core/src/input/inputplumber/dbus_device.rs @@ -57,7 +57,7 @@ impl DBusDevice { /// Create a new [DBusDevice] with the given DBus path pub fn from_path(path: GString) -> Gd { // Create a channel to communicate with the signals task - log::info!("DBusDevice created with path: {path}"); + log::debug!("DBusDevice created with path: {path}"); let (tx, rx) = channel(); let dbus_path = path.clone().into(); @@ -89,7 +89,7 @@ impl DBusDevice { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists with path '{res_path}', loading that instead"); + log::debug!("Resource already exists with path '{res_path}', loading that instead"); let device: Gd = res.cast(); device } else { @@ -188,7 +188,7 @@ async fn run(tx: Sender, path: String) -> Result<(), RunError> { break; } } - log::info!("DBusDevice input_event task stopped"); + log::debug!("DBusDevice input_event task stopped"); }); let signals_tx = tx.clone(); @@ -210,7 +210,7 @@ async fn run(tx: Sender, path: String) -> Result<(), RunError> { break; } } - log::info!("DBusDevice touch_event task stopped"); + log::debug!("DBusDevice touch_event task stopped"); }); Ok(()) diff --git a/extensions/core/src/input/inputplumber/event_device.rs b/extensions/core/src/input/inputplumber/event_device.rs index 213a4aa9..1d820ff0 100644 --- a/extensions/core/src/input/inputplumber/event_device.rs +++ b/extensions/core/src/input/inputplumber/event_device.rs @@ -76,7 +76,7 @@ impl EventDevice { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists, loading that instead"); + log::debug!("Resource already exists, loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/input/inputplumber/keyboard_device.rs b/extensions/core/src/input/inputplumber/keyboard_device.rs index dc52ce68..9137d611 100644 --- a/extensions/core/src/input/inputplumber/keyboard_device.rs +++ b/extensions/core/src/input/inputplumber/keyboard_device.rs @@ -60,7 +60,7 @@ impl KeyboardDevice { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists, loading that instead"); + log::debug!("Resource already exists, loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/input/inputplumber/mouse_device.rs b/extensions/core/src/input/inputplumber/mouse_device.rs index 8cf4c0cc..149d2ca5 100644 --- a/extensions/core/src/input/inputplumber/mouse_device.rs +++ b/extensions/core/src/input/inputplumber/mouse_device.rs @@ -60,7 +60,7 @@ impl MouseDevice { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists, loading that instead"); + log::debug!("Resource already exists, loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/performance/powerstation.rs b/extensions/core/src/performance/powerstation.rs index 52dbd8db..5400ea9d 100644 --- a/extensions/core/src/performance/powerstation.rs +++ b/extensions/core/src/performance/powerstation.rs @@ -10,7 +10,7 @@ use std::{ }; use cpu::Cpu; -use godot::prelude::*; +use godot::{classes::Engine, prelude::*}; use gpu::Gpu; use zbus::names::BusName; @@ -27,6 +27,7 @@ enum Signal { Stopped, } +/// PowerStation dbus proxy #[derive(GodotClass)] #[class(base=Resource)] pub struct PowerStationInstance { @@ -133,6 +134,21 @@ impl IResource for PowerStationInstance { // Create a channel to communicate with the service let (tx, rx) = channel(); + let conn = get_dbus_system_blocking().ok(); + + // Don't run in the editor + let engine = Engine::singleton(); + if engine.is_editor_hint() { + return Self { + base, + rx, + conn, + cpu_instance: Default::default(), + gpu_instance: Default::default(), + cpu: Default::default(), + gpu: Default::default(), + }; + } // Spawn a task using the shared tokio runtime to listen for signals RUNTIME.spawn(async move { @@ -147,7 +163,6 @@ impl IResource for PowerStationInstance { let gpu = Some(Gpu::new(POWERSTATION_GPU_PATH)); // Create a new PowerStation instance - let conn = get_dbus_system_blocking().ok(); Self { base, rx, diff --git a/extensions/core/src/performance/powerstation/cpu.rs b/extensions/core/src/performance/powerstation/cpu.rs index 05256751..943f4907 100644 --- a/extensions/core/src/performance/powerstation/cpu.rs +++ b/extensions/core/src/performance/powerstation/cpu.rs @@ -117,7 +117,7 @@ impl Cpu { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists, loading that instead"); + log::trace!("Resource already exists, loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/performance/powerstation/cpu_core.rs b/extensions/core/src/performance/powerstation/cpu_core.rs index ef969eae..2de59816 100644 --- a/extensions/core/src/performance/powerstation/cpu_core.rs +++ b/extensions/core/src/performance/powerstation/cpu_core.rs @@ -90,7 +90,7 @@ impl CpuCore { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists, loading that instead"); + log::trace!("Resource already exists, loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/performance/powerstation/gpu.rs b/extensions/core/src/performance/powerstation/gpu.rs index 61472ecc..3a872582 100644 --- a/extensions/core/src/performance/powerstation/gpu.rs +++ b/extensions/core/src/performance/powerstation/gpu.rs @@ -69,7 +69,7 @@ impl Gpu { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists, loading that instead"); + log::trace!("Resource already exists, loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/performance/powerstation/gpu_card.rs b/extensions/core/src/performance/powerstation/gpu_card.rs index 4d65c0df..d53f7422 100644 --- a/extensions/core/src/performance/powerstation/gpu_card.rs +++ b/extensions/core/src/performance/powerstation/gpu_card.rs @@ -216,7 +216,7 @@ impl GpuCard { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists, loading that instead"); + log::trace!("Resource already exists, loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/performance/powerstation/gpu_connector.rs b/extensions/core/src/performance/powerstation/gpu_connector.rs index 52e7616d..043b02f3 100644 --- a/extensions/core/src/performance/powerstation/gpu_connector.rs +++ b/extensions/core/src/performance/powerstation/gpu_connector.rs @@ -106,7 +106,7 @@ impl GpuConnector { let mut resource_loader = ResourceLoader::singleton(); if resource_loader.exists(res_path.as_str()) { if let Some(res) = resource_loader.load(res_path.as_str()) { - log::info!("Resource already exists, loading that instead"); + log::trace!("Resource already exists, loading that instead"); let device: Gd = res.cast(); device } else { diff --git a/extensions/core/src/power/upower.rs b/extensions/core/src/power/upower.rs index c267943c..85c94090 100644 --- a/extensions/core/src/power/upower.rs +++ b/extensions/core/src/power/upower.rs @@ -4,7 +4,7 @@ use std::{ time::Duration, }; -use godot::prelude::*; +use godot::{classes::Engine, prelude::*}; use zbus::names::BusName; use crate::{ @@ -25,6 +25,7 @@ enum Signal { Stopped, } +/// UPower dbus proxy for power management #[derive(GodotClass)] #[class(base=Resource)] pub struct UPowerInstance { @@ -70,8 +71,7 @@ impl UPowerInstance { proxy.on_battery().ok().unwrap_or_default() } - /// Get the object to the "display device", a composite device that represents - /// the status icon to show in desktop environments. + /// Get the object to the "display device", a composite device that represents the status icon to show in desktop environments. #[func] pub fn get_display_device(&mut self) -> Gd { if let Some(device) = self.devices.get(DISPLAY_DEVICE_PATH) { @@ -83,8 +83,7 @@ impl UPowerInstance { device } - /// Process UPower signals and emit them as Godot signals. This method - /// should be called every frame in the "_process" loop of a node. + /// Process UPower signals and emit them as Godot signals. This method should be called every frame in the `_process` loop of a node. #[func] fn process(&mut self) { // Drain all messages from the channel to process them @@ -141,6 +140,19 @@ impl IResource for UPowerInstance { // Create a channel to communicate with the service let (tx, rx) = channel(); + let conn = get_dbus_system_blocking().ok(); + + // Don't run in the editor + let engine = Engine::singleton(); + if engine.is_editor_hint() { + return Self { + base, + rx, + conn, + devices: Default::default(), + on_battery: Default::default(), + }; + } // Spawn a task using the shared tokio runtime to listen for signals RUNTIME.spawn(async move { @@ -150,7 +162,6 @@ impl IResource for UPowerInstance { }); // Create a new UPower instance - let conn = get_dbus_system_blocking().ok(); Self { base, rx, diff --git a/extensions/core/src/resource/resource_processor.rs b/extensions/core/src/resource/resource_processor.rs index e283ab35..a378f18b 100644 --- a/extensions/core/src/resource/resource_processor.rs +++ b/extensions/core/src/resource/resource_processor.rs @@ -2,10 +2,11 @@ use godot::{obj::WithBaseField, prelude::*}; use super::resource_registry::ResourceRegistry; -/// The [ResourceProcessor] allows Godot [Resource] objects to run a process -/// function every frame. Resources must register with the [ResourceRegistry] -/// associated with this [ResourceProcessor] in order to be processed from -/// the scene tree. +/// Helper node to allow [Resource] objects to run during the process loop. +/// +/// The [ResourceProcessor] allows Godot [Resource] objects to run a [method process] function every frame. By design, Godot [Resource] objects do not have access to the scene tree and must be "invited" in by a [Node] in the scene. This node serves as that entrypoint, and should be added to the scene tree to execute [method process] on any [Resource] objects registered with a [ResourceRegistry]. +/// +/// Resources must register with the [ResourceRegistry] using [method ResourceRegistry.register] associated with this [ResourceProcessor] in order to be processed from the scene tree. #[derive(GodotClass)] #[class(init, base=Node)] pub struct ResourceProcessor { diff --git a/extensions/core/src/resource/resource_registry.rs b/extensions/core/src/resource/resource_registry.rs index 05dd4136..4ad5a8c3 100644 --- a/extensions/core/src/resource/resource_registry.rs +++ b/extensions/core/src/resource/resource_registry.rs @@ -1,5 +1,17 @@ use godot::prelude::*; +/// Class for registering [Resource] objects with a [method process] method that will get executed every frame by a [ResourceProcessor]. +/// +/// By design, [Resource] objects do not have access to the scene tree in order to be updated every frame during the [method process] loop. The [ResourceRegistry] provides a way for [Resource] objects to register themselves to have their [method process] method called every frame by a [ResourceProcessor] node. +/// +/// By saving the [ResourceRegistry] as a `.tres` file, [Resource] objects anywhere in the project can load the same [ResourceRegistry] instance and register themselves to run their [method process] method every frame by a [ResourceProcessor] node in the scene tree. +/// +/// Example +/// +/// [codeblock] +/// var registry := load("res://path/to/registry.tres") as ResourceRegistry +/// registry.register(self) +/// [/codeblock] #[derive(GodotClass)] #[class(init, base=Resource)] pub struct ResourceRegistry { @@ -15,7 +27,7 @@ impl ResourceRegistry { #[signal] fn child_removed(child: Gd); - /// Register the given resource with the registry. The given resource will have its "process()" method called every frame by a [ResourceProcessor]. + /// Register the given resource with the registry. The given resource will have its [method process] method called every frame by a [ResourceProcessor] in the scene tree. #[func] pub fn register(&mut self, resource: Gd) { if !resource.has_method("process") { @@ -36,7 +48,7 @@ impl ResourceRegistry { self.resources.erase(&resource); } - /// Calls the "process()" method on all registered resources. This should be called from a [Node] in the scene tree like the [ResourceProcessor]. + /// Calls the `process()` method on all registered [Resource] objects. This should be called from a [Node] in the scene tree like the [ResourceProcessor]. #[func] pub fn process(&mut self, delta: f64) { for mut resource in self.resources.iter_shared() { @@ -44,8 +56,7 @@ impl ResourceRegistry { } } - /// Adds the given node to the [ResourceProcessor] node associated with this registry. - /// This provides a way for resources to add nodes into the scene tree. + /// Adds the given node to the [ResourceProcessor] node associated with this registry. This provides a way for resources to add nodes into the scene tree. #[func] pub fn add_child(&mut self, child: Gd) { self.child_nodes.push(&child); diff --git a/extensions/core/src/system.rs b/extensions/core/src/system.rs index e3beddbb..5fa75f96 100644 --- a/extensions/core/src/system.rs +++ b/extensions/core/src/system.rs @@ -1,3 +1,2 @@ -pub mod command; pub mod pty; pub mod subreaper; diff --git a/extensions/core/src/system/command.rs b/extensions/core/src/system/command.rs deleted file mode 100644 index e6f77648..00000000 --- a/extensions/core/src/system/command.rs +++ /dev/null @@ -1,44 +0,0 @@ -//use std::sync::mpsc::Receiver; -// -//use godot::prelude::*; - -//// Signals that can be emitted -//#[derive(Debug)] -//enum Signal { -// InputEvent { -// type_code: String, -// value: f64, -// }, -// TouchEvent { -// type_code: String, -// index: u32, -// is_touching: bool, -// pressure: f64, -// x: f64, -// y: f64, -// }, -//} -// -//#[derive(GodotClass)] -//#[class(base=RefCounted)] -//pub struct Command { -// base: Base, -// path: String, -// rx: Receiver, -//} -// -//#[godot_api] -//impl Command { -// #[signal] -// fn input_event(type_code: GString, value: f64); -// -// #[signal] -// fn touch_event( -// type_code: GString, -// index: i64, -// is_touching: bool, -// pressure: f64, -// x: f64, -// y: f64, -// ); -//} diff --git a/extensions/core/src/system/pty.rs b/extensions/core/src/system/pty.rs index 73356bf1..66d2c1cc 100644 --- a/extensions/core/src/system/pty.rs +++ b/extensions/core/src/system/pty.rs @@ -226,7 +226,7 @@ impl Pty { // Spawn a task to read/write from/to the PTY let signals_tx = self.tx.clone(); RUNTIME.spawn(async move { - log::info!("Task spawned to read/write PTY"); + log::debug!("Task spawned to read/write PTY"); // Create readers/writers let output = std::fs::File::from(master.try_clone().unwrap()); diff --git a/extensions/reaper/src/main.rs b/extensions/reaper/src/main.rs index 89e0d56e..865e61cc 100644 --- a/extensions/reaper/src/main.rs +++ b/extensions/reaper/src/main.rs @@ -87,6 +87,7 @@ fn main() { } // Execute the command + #[allow(irrefutable_let_patterns)] if let Err(e) = execvp(cmd.as_c_str(), c_args.as_slice()) { panic!("reaper: failed executing command: {e:?}"); }