Skip to content

kllarena07/frontmost

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Frontmost

✍ About

A crate that dynamically captures the currently focused application on macOS, powered by objc2, objc2_foundation, and objc2_app_kit Rust bindings.

🤔 Why Frontmost

One might assume that you could simply use the applications crate by placing ctx.get_frontmost_application().unwrap() inside a loop and call it a day. However, this approach does not work as expected in practice.

Why? Because macOS uses an event-driven architecture, and a blocking loop prevents the main NSRunLoop from processing events. The NSRunLoop powers macOS's asynchronous notification system, so blocking it disrupts normal event handling.

To work with this architecture, the code instead creates an observer (such as an NSWorkspace notification observer) that triggers when the user switches focus to a different application, specifically utilizing the NSWorkspaceDidActivateApplicationNotification notification. This allows your code to respond to application changes without blocking the run loop.

📖 How to Use

Check examples for an example of frontmost put into use.

  1. Bring the frontmost module into scope
use frontmost::app::FrontmostApp;
use frontmost::{Detector, start_nsrunloop};
  1. Define your application struct that will hold state
#[derive(Debug)]
struct MyApp {
    frontmost: String,
}
  1. Implement the FrontmostApp trait for your struct
  • set_frontmost(&mut self, new_value: &str) - Called when app switches, receives app name
  • update(&self) - Called after setting, for side effects like logging or triggers
impl FrontmostApp for MyApp {
    fn set_frontmost(&mut self, new_value: &str) {
        self.frontmost = new_value.to_string();
    }
    
    fn update(&self) {
        println!("Application activated: {}", self.frontmost);
    }
}
  1. Initialize the Detector by passing a boxed instance
Detector::init(Box::new(my_app));
  1. Start the event loop using the start_nsrunloop!() macro
start_nsrunloop!();

Complete Example

use frontmost::app::FrontmostApp;
use frontmost::{Detector, start_nsrunloop};

#[derive(Debug)]
struct App {
    frontmost: String,
}

impl FrontmostApp for App {
    fn set_frontmost(&mut self, new_value: &str) {
        self.frontmost = new_value.to_string();
    }
    
    fn update(&self) {
        println!("Application activated: {}", self.frontmost);
    }
}

fn main() {
    let my_app = App {
        frontmost: String::new(),
    };

    Detector::init(Box::new(my_app));

    println!("Monitoring application activations. Press Ctrl+C to stop.");
    start_nsrunloop!();
}

👾 Bugs or vulnerabilities

If you find any bugs or vulnerabilities, please contact me on my Twitter using the link below.

Made with ❤️ by krayondev

About

dynamically detecting the currently focused app, for macos

Resources

License

Stars

4 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages