use crate::models::ScreenshotResponse;
use crate::{Error, Result};
use image;
use log::{debug, info, error};
use tauri::Runtime;
use crate::desktop::{ScreenshotContext, create_success_response};
use crate::platform::shared::{get_window_title, handle_screenshot_task};
use crate::shared::ScreenshotParams;
use crate::tools::take_screenshot::process_image;
/// Take a screenshot on Linux/Unix using xcap.
pub async fn take_screenshot<R: Runtime>(
params: ScreenshotParams,
window_context: ScreenshotContext<R>,
) -> Result<ScreenshotResponse> {
let params_clone = params.clone();
let window_clone = window_context.window.clone();
let window_label = params
.window_label
.clone()
.unwrap_or_else(|| "main".to_string());
let application_name = params.application_name.clone().unwrap_or_default();
handle_screenshot_task(move || {
let window_title = get_window_title(&window_clone)?;
info!("[TAURI-MCP] Looking for window with title: {} (label: {})", window_title, window_label);
let xcap_windows = match xcap::Window::all() {
Ok(windows) => windows,
Err(e) => return Err(Error::WindowOperationFailed(format!("Failed to get window list: {}", e))),
};
info!("[TAURI-MCP] Found {} windows through xcap", xcap_windows.len());
if let Some(window) = find_window(&xcap_windows, &window_title, &application_name) {
let image = match window.capture_image() {
Ok(img) => img,
Err(e) => return Err(Error::WindowOperationFailed(format!("Failed to capture window image: {}", e))),
};
info!("[TAURI-MCP] Captured window image: {}x{}", image.width(), image.height());
let dynamic_image = image::DynamicImage::ImageRgba8(image);
process_image(dynamic_image, ¶ms_clone).map(create_success_response)
} else {
Err(Error::WindowOperationFailed(
"Window not found. Ensure the window is visible and not minimized.".to_string()
))
}
}).await
}
fn find_window(
xcap_windows: &[xcap::Window],
window_title: &str,
application_name: &str,
) -> Option<xcap::Window> {
let app_lc = application_name.to_lowercase();
let title_lc = window_title.to_lowercase();
debug!("[TAURI-MCP] Searching for window title='{}' app='{}'", window_title, application_name);
// Pass 1: exact app name match
if !app_lc.is_empty() {
for w in xcap_windows {
if w.is_minimized() { continue; }
if w.app_name().to_lowercase() == app_lc {
info!("[TAURI-MCP] Found by exact app name: '{}'", w.app_name());
return Some(w.clone());
}
}
}
// Pass 2: app name contains search term
for w in xcap_windows {
if w.is_minimized() { continue; }
let name_lc = w.app_name().to_lowercase();
if (!app_lc.is_empty() && name_lc.contains(&app_lc))
|| name_lc.contains(&title_lc)
{
info!("[TAURI-MCP] Found by partial app name: '{}'", w.app_name());
return Some(w.clone());
}
}
// Pass 3: window title match
for w in xcap_windows {
if w.is_minimized() { continue; }
let wt = w.title().to_lowercase();
if wt.contains(&title_lc) || (!app_lc.is_empty() && wt.contains(&app_lc)) {
info!("[TAURI-MCP] Found by window title: '{}'", w.title());
return Some(w.clone());
}
}
error!("[TAURI-MCP] No matching window found for '{}'", window_title);
None
}