diff --git a/crates/ffi/include/agent_desktop.h b/crates/ffi/include/agent_desktop.h index f720d26..be5ad83 100644 --- a/crates/ffi/include/agent_desktop.h +++ b/crates/ffi/include/agent_desktop.h @@ -196,6 +196,12 @@ typedef struct AdPoint { double y; } AdPoint; +/* + * Caller-allocated drag parameters. Zero-initialize the whole struct before + * setting fields: `duration_ms`/`drop_delay_ms` treat 0 as the adapter-default + * sentinel, so stack garbage in an unset field would become a real delay. + * Validate layout with `AD_DRAG_PARAMS_SIZE` / `ad_drag_params_size()`. + */ typedef struct AdDragParams { struct AdPoint from; struct AdPoint to; @@ -205,6 +211,10 @@ typedef struct AdDragParams { uint64_t drop_delay_ms; } AdDragParams; +#define AD_DRAG_PARAMS_SIZE (sizeof(AdDragParams)) + +uintptr_t ad_drag_params_size(void); + /** * Action dispatched by `ad_execute_action`. * diff --git a/crates/ffi/src/types/drag_params.rs b/crates/ffi/src/types/drag_params.rs index 43ebafb..4b63880 100644 --- a/crates/ffi/src/types/drag_params.rs +++ b/crates/ffi/src/types/drag_params.rs @@ -1,6 +1,11 @@ use crate::types::point::AdPoint; use agent_desktop_core::action::{DragParams as CoreDragParams, Point as CorePoint}; +/// Caller-allocated drag parameters. Callers must zero-initialize the whole +/// struct before setting fields so unset numeric fields read as the `0` +/// adapter-default sentinel rather than stack garbage. Verify layout against +/// `AD_DRAG_PARAMS_SIZE` / `ad_drag_params_size()` when binding from a language +/// whose struct layout may diverge. #[repr(C)] pub struct AdDragParams { pub from: AdPoint, @@ -9,6 +14,15 @@ pub struct AdDragParams { pub drop_delay_ms: u64, } +pub const AD_DRAG_PARAMS_SIZE: usize = 48; + +const _: () = assert!(std::mem::size_of::() == AD_DRAG_PARAMS_SIZE); + +#[unsafe(no_mangle)] +pub extern "C" fn ad_drag_params_size() -> usize { + std::mem::size_of::() +} + impl AdDragParams { /// Converts the C drag params into the core type. `duration_ms` and /// `drop_delay_ms` use `0` as the "adapter default" sentinel because the