An open API service indexing awesome lists of open source software.

https://github.com/efjerryyang/winshift-rs


https://github.com/efjerryyang/winshift-rs

Last synced: 5 months ago
JSON representation

Awesome Lists containing this project

README

          

# winshift

[![Crates.io](https://img.shields.io/crates/v/winshift)](https://crates.io/crates/winshift)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

A cross-platform library for monitoring window focus changes.

## Features

- Native window focus tracking on Linux via X11 (reference implementation)
- macOS support via Accessibility API (requires app tracking workaround)
- Event-driven callback system
- Minimal overhead window monitoring
- Optional embedded active window info in callbacks (macOS)

Note: The app tracking functionality on macOS exists solely to work around
platform limitations for reliable window focus detection.

## Supported Platforms

- **Linux**: Native window focus tracking via X11 (reference implementation)
- **macOS**: Window tracking via Accessibility API workaround (requires app tracking)
- **Windows**: Planned (not yet implemented)

## Quick Start

```sh
cargo add winshift
```

See the [Examples](#examples) section for usage patterns.

## Examples

### Illustrative Usage Pattern

This simplified example shows the basic structure. For complete, working examples see the [examples/](examples/) directory.

```rust,no_run
use winshift::{FocusChangeHandler, WindowFocusHook};
use std::sync::Arc;

struct MyHandler;

impl FocusChangeHandler for MyHandler {
fn on_app_change(&self, pid: i32, app_name: String) {
println!("App changed: {} (PID: {})", app_name, pid);
}

fn on_window_change(&self, window_title: String) {
println!("Window changed: {}", window_title);
}
}

fn main() -> Result<(), winshift::WinshiftError> {
let handler = Arc::new(MyHandler);
let hook = WindowFocusHook::new(handler);

// Start monitoring (runs in current thread)
hook.run()?;

// On macOS, you can stop with:
// winshift::stop_hook();

Ok(())
}
```

### macOS: Embedded ActiveWindowInfo (no extra queries)

When enabled, macOS event callbacks also include the full `ActiveWindowInfo` so apps don’t need to call `get_active_window_info()` after each event. This reduces overhead and simplifies consumers like chronicle.

How to enable:

```rust
use winshift::{FocusChangeHandler, WindowFocusHook, WindowHookConfig};

struct Handler;

impl FocusChangeHandler for Handler {
fn on_app_change(&self, pid: i32, app_name: String) {
println!("app: {app_name} ({pid})");
}
fn on_window_change(&self, title: String) {
println!("win: {title}");
}

// macOS-only rich payloads
#[cfg(target_os = "macos")]
fn on_app_change_info(&self, info: winshift::ActiveWindowInfo) {
println!("app+info: {} pid={} exe={} wid={} bounds=({},{} {}x{})",
info.app_name, info.process_id, info.proc_path, info.window_id,
info.bounds.x, info.bounds.y, info.bounds.width, info.bounds.height);
}
#[cfg(target_os = "macos")]
fn on_window_change_info(&self, info: winshift::ActiveWindowInfo) {
println!("win+info: '{}' exe={}", info.title, info.proc_path);
}
}

fn main() -> Result<(), winshift::WinshiftError> {
winshift::env_logger::init();
let mut cfg = WindowHookConfig::default();
cfg.embed_active_info = true; // opt-in to richer payloads
let hook = WindowFocusHook::with_config(Handler, cfg);
hook.run()
}
```

See `examples/embed_info_monitor.rs` for a complete example.

**Important Notes**:

1. Handler must be thread-safe (use Arc/RwLock if needed)
2. On macOS, call `stop_hook()` to clean up
3. See [examples/](examples/) for complete implementations
4. Linux uses same API but doesn't require combined tracking
5. Note: Implementation uses unsafe code and assumes single-threaded usage for now
6. Embedded info callbacks are currently macOS-only; other platforms still receive the base callbacks

## Platform Notes

### Linux (Reference Implementation)

- Pure window focus tracking via X11 protocol
- No app tracking required
- Tested with common desktop environments (GNOME, KDE, etc.)

### macOS Requirements

- Requires Accessibility permissions
- Enable in System Preferences > Security & Privacy > Privacy > Accessibility

### Windows

- Not yet implemented (planned for future release)

## API Documentation

Full API documentation is available via `cargo doc --open`.

## Contributing

Contributions are welcome! Please open issues or pull requests on GitHub.

## License

MIT - See [LICENSE](LICENSE) for details.