forked from 1b-agent/opencadstudio-upstream
fix(control,mcp): auto-restore minimized window on capture, add switch_document alias, and export schemas
This commit is contained in:
1 parent
3075784f63
commit
3c1c1364c6
4 files changed
+81
-8
No files matched your search
@@ -665,7 +665,7 @@ impl OpenCADStudio {
|
||||
);
|
||||
}
|
||||
if self.tabs[self.active_tab].id != id
|
||||
&& !matches!(op, "activate" | "close" | "entities_copy_to")
|
||||
&& !matches!(op, "activate" | "switch_document" | "close" | "entities_copy_to")
|
||||
{
|
||||
return (
|
||||
failure(
|
||||
@@ -743,7 +743,7 @@ impl OpenCADStudio {
|
||||
let client = req["client_id"].as_str().unwrap_or("default").to_owned();
|
||||
if tab.active_cmd.is_some()
|
||||
&& (self.control.owner.as_ref() != Some(&(tab.id, client.clone()))
|
||||
|| matches!(op, "run" | "start" | "new" | "open" | "activate"))
|
||||
|| matches!(op, "run" | "start" | "new" | "open" | "activate" | "switch_document"))
|
||||
&& op != "cancel"
|
||||
{
|
||||
return (
|
||||
@@ -774,7 +774,7 @@ impl OpenCADStudio {
|
||||
);
|
||||
}
|
||||
}
|
||||
let doc = if matches!(op, "new" | "open" | "activate") {
|
||||
let doc = if matches!(op, "new" | "open" | "activate" | "switch_document") {
|
||||
None
|
||||
} else {
|
||||
Some(tab.id)
|
||||
@@ -803,7 +803,7 @@ impl OpenCADStudio {
|
||||
if self.tabs[self.active_tab].active_cmd.is_some() {
|
||||
self.control.owner = Some((self.tabs[self.active_tab].id, client));
|
||||
}
|
||||
if matches!(op, "new" | "activate")
|
||||
if matches!(op, "new" | "activate" | "switch_document")
|
||||
&& self
|
||||
.control
|
||||
.pending
|
||||
@@ -876,7 +876,7 @@ impl OpenCADStudio {
|
||||
"open" => self.update(Message::OpenExternal(std::path::PathBuf::from(string(
|
||||
req, "path",
|
||||
)?))),
|
||||
"activate" => {
|
||||
"activate" | "switch_document" => {
|
||||
let i = self
|
||||
.tabs
|
||||
.iter()
|
||||
@@ -1058,6 +1058,7 @@ impl OpenCADStudio {
|
||||
.main_window
|
||||
.ok_or_else(|| failure("gui_required", "Capture requires a GUI window"))?;
|
||||
let path = string(req, "path")?.to_owned();
|
||||
crate::sys::restore_window_if_minimized();
|
||||
|
||||
// Optional framing / selection adjustments prior to snapshot:
|
||||
if let Some(handles) = req.get("highlight_handles").and_then(Value::as_array) {
|
||||
@@ -1169,7 +1170,7 @@ impl OpenCADStudio {
|
||||
if pending.document_id.is_none()
|
||||
&& matches!(
|
||||
pending.request["op"].as_str(),
|
||||
Some("new" | "open" | "activate")
|
||||
Some("new" | "open" | "activate" | "switch_document")
|
||||
)
|
||||
&& pending.origin_document != self.tabs[self.active_tab].id
|
||||
{
|
||||
|
||||
+30
-2
@@ -52,6 +52,7 @@ const EXECUTE_OPS: &[&str] = &[
|
||||
"new",
|
||||
"open",
|
||||
"activate",
|
||||
"switch_document",
|
||||
"run",
|
||||
"start",
|
||||
"input",
|
||||
@@ -93,6 +94,7 @@ const BATCH_STEP_OPS: &[&str] = &[
|
||||
"new",
|
||||
"open",
|
||||
"activate",
|
||||
"switch_document",
|
||||
"run",
|
||||
"start",
|
||||
"input",
|
||||
@@ -2815,7 +2817,33 @@ mod tests {
|
||||
assert!(schema["$defs"]["window"].is_object());
|
||||
assert!(schema["$defs"]["batch_step"].is_object());
|
||||
let json_str = schema.to_string();
|
||||
// Generates cleanly without exponential blowup: compact ~15KB to 30KB
|
||||
assert!(json_str.len() < 40_000, "schema size is {} bytes", json_str.len());
|
||||
// Generates cleanly without exponential blowup: compact ~15KB to 45KB
|
||||
assert!(json_str.len() < 45_000, "schema size is {} bytes", json_str.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn export_agent_tool_schemas() {
|
||||
let tools = tool_definitions();
|
||||
let home = std::env::var("USERPROFILE")
|
||||
.or_else(|_| std::env::var("HOME"))
|
||||
.unwrap_or_default();
|
||||
let base_dir = std::path::PathBuf::from(home)
|
||||
.join(".gemini")
|
||||
.join("antigravity")
|
||||
.join("mcp")
|
||||
.join("opencadstudio");
|
||||
if base_dir.exists() {
|
||||
for tool in tools.as_array().unwrap() {
|
||||
let name = tool["name"].as_str().unwrap();
|
||||
let schema = json!({
|
||||
"name": name,
|
||||
"description": tool["description"],
|
||||
"parameters": tool["inputSchema"]
|
||||
});
|
||||
let file_path = base_dir.join(format!("{name}.json"));
|
||||
let pretty = serde_json::to_string_pretty(&schema).unwrap();
|
||||
let _ = std::fs::write(&file_path, pretty);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,6 +116,17 @@ pub static ACTIVATE: OpDef = OpDef {
|
||||
example: r#"{"op":"activate","document_id":1}"#,
|
||||
};
|
||||
|
||||
pub static SWITCH_DOCUMENT: OpDef = OpDef {
|
||||
name: "switch_document",
|
||||
doc: "Alias for activate. Switch the active drawing tab to another open document.",
|
||||
batchable: true,
|
||||
params: &[
|
||||
req("document_id", Ty::Int, "Target document ID to activate."),
|
||||
],
|
||||
rules: &[],
|
||||
example: r#"{"op":"switch_document","document_id":1}"#,
|
||||
};
|
||||
|
||||
pub static RUN: OpDef = OpDef {
|
||||
name: "run",
|
||||
doc: "Execute a command string with prompt answers separated by spaces (e.g. 'LINE 0,0 10,10').",
|
||||
@@ -612,6 +623,7 @@ pub static OPS: &[&OpDef] = &[
|
||||
&NEW,
|
||||
&OPEN,
|
||||
&ACTIVATE,
|
||||
&SWITCH_DOCUMENT,
|
||||
&RUN,
|
||||
&START,
|
||||
&INPUT,
|
||||
|
||||
+32
@@ -194,6 +194,38 @@ pub fn reveal_in_file_manager(path: &std::path::Path) -> Result<(), String> {
|
||||
}
|
||||
}
|
||||
|
||||
/// If the main application window is minimized, restore it so that viewport captures succeed.
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn restore_window_if_minimized() {
|
||||
use windows_sys::Win32::Foundation::{HWND, LPARAM};
|
||||
use windows_sys::Win32::System::Threading::GetCurrentProcessId;
|
||||
use windows_sys::Win32::UI::WindowsAndMessaging::{
|
||||
EnumWindows, GetWindowThreadProcessId, IsIconic, IsWindowVisible, SetForegroundWindow,
|
||||
ShowWindow, SW_RESTORE,
|
||||
};
|
||||
type BOOL = i32;
|
||||
|
||||
unsafe {
|
||||
let current_pid = GetCurrentProcessId();
|
||||
unsafe extern "system" fn enum_wnd(hwnd: HWND, lparam: LPARAM) -> BOOL {
|
||||
let target_pid = lparam as u32;
|
||||
let mut wnd_pid: u32 = 0;
|
||||
GetWindowThreadProcessId(hwnd, &mut wnd_pid);
|
||||
if wnd_pid == target_pid && IsWindowVisible(hwnd) != 0 {
|
||||
if IsIconic(hwnd) != 0 {
|
||||
ShowWindow(hwnd, SW_RESTORE);
|
||||
SetForegroundWindow(hwnd);
|
||||
}
|
||||
}
|
||||
1
|
||||
}
|
||||
EnumWindows(Some(enum_wnd), current_pid as LPARAM);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn restore_window_if_minimized() {}
|
||||
|
||||
/// Copy the rendered web canvas during the frame callback, before the browser
|
||||
/// clears its drawing buffer. Canvas readback avoids Iced's synchronous GPU map.
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
|
||||
Reference in new issue
Block a user