Skip to content

Instantly share code, notes, and snippets.

@mpottinger
Last active July 21, 2025 12:48
Show Gist options
  • Select an option

  • Save mpottinger/d8d993f298be22fdea5ff9ab11f9b7b3 to your computer and use it in GitHub Desktop.

Select an option

Save mpottinger/d8d993f298be22fdea5ff9ab11f9b7b3 to your computer and use it in GitHub Desktop.
macOS Active Apps - Rust library for getting visible applications with windows on screen

macOS Active Apps Library

A Rust library for getting truly visible applications on macOS - those with windows currently on top of the screen.

Features

  • Get all visible windows currently on screen (not just running apps)
  • Get unique application names with visible windows
  • Get the frontmost (topmost) window with details
  • Detect JetBrains IDEs specifically
  • Get the frontmost JetBrains IDE if one is focused

Usage

Add to your Cargo.toml:

[dependencies]
core-graphics = "0.25.0"
core-foundation = "0.10.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

Basic usage:

use macos_active_apps::*;

// Get apps with visible windows
let visible_apps = get_top_level_visible_apps();
println!("Visible apps: {:?}", visible_apps);

// Get frontmost window
if let Some(frontmost) = get_frontmost_window() {
    println!("Frontmost: {} - {}", frontmost.app_name, frontmost.window_title);
    println!("Position: ({}, {})", frontmost.bounds.origin.x, frontmost.bounds.origin.y);
    println!("Size: {}x{}", frontmost.bounds.size.width, frontmost.bounds.size.height);
}

// Get visible JetBrains IDEs
let ides = get_visible_jetbrains_ides();
println!("JetBrains IDEs: {:?}", ides);

// Check if a JetBrains IDE is frontmost
if let Some(ide) = get_frontmost_jetbrains_ide() {
    println!("Frontmost IDE: {}", ide);
}

Run Test

cargo run --bin test

What Makes This Different

Unlike other libraries that just list running applications, this one uses Core Graphics to get only applications that actually have visible windows on screen. This is useful for:

  • Window management tools
  • Screen recording apps
  • Productivity tools that need to know what's actually visible
  • IDE/editor detection for development tools

Platform

  • macOS only (uses Core Graphics framework)
  • Requires macOS 10.6+ (for Core Graphics APIs)
[package]
name = "macos_active_apps"
version = "0.1.0"
edition = "2021"
[lib]
name = "macos_active_apps"
path = "src/lib.rs"
# Optional test binary for direct testing
[[bin]]
name = "test"
path = "src/bin/test.rs"
[dependencies]
core-graphics = "0.25.0"
core-foundation = "0.10.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
/*!
Get truly visible applications - those with windows currently on top of the screen.
This uses the Core Graphics framework's CGWindowListCopyWindowInfo to get only windows
that are actually visible on screen, not just running applications.
*/
use core_graphics::window::{
kCGWindowListExcludeDesktopElements, kCGWindowListOptionOnScreenOnly, CGWindowListCopyWindowInfo,
};
use core_graphics::geometry::{CGRect, CGPoint, CGSize};
use core_foundation::array::CFArray;
use core_foundation::dictionary::CFDictionary;
use core_foundation::string::CFString;
use core_foundation::base::{TCFType, CFTypeRef};
use core_foundation::number::CFNumber;
use std::collections::HashSet;
#[derive(Debug, Clone)]
pub struct WindowInfo {
pub app_name: String,
pub window_title: String,
pub pid: i64,
pub window_id: u32,
pub bounds: CGRect,
pub layer: i64,
}
impl WindowInfo {
fn from_cf_dict(dict: &CFDictionary<CFString, CFTypeRef>) -> Option<Self> {
// Helper function to safely extract string values
let get_string = |key: &str| -> String {
let cf_key = CFString::new(key);
dict.find(cf_key)
.and_then(|value_ref| {
let cf_string = unsafe { CFString::wrap_under_get_rule(*value_ref as *const _) };
Some(cf_string.to_string())
})
.unwrap_or_default()
};
// Helper function to safely extract number values
let get_number = |key: &str| -> i64 {
let cf_key = CFString::new(key);
dict.find(cf_key)
.and_then(|value_ref| {
let cf_number = unsafe { CFNumber::wrap_under_get_rule(*value_ref as *const _) };
cf_number.to_i64()
})
.unwrap_or(0)
};
// Helper function to safely extract float values
let _get_float = |key: &str| -> f64 {
let cf_key = CFString::new(key);
dict.find(cf_key)
.and_then(|value_ref| {
let cf_number = unsafe { CFNumber::wrap_under_get_rule(*value_ref as *const _) };
cf_number.to_f64()
})
.unwrap_or(0.0)
};
let app_name = get_string("kCGWindowOwnerName");
let window_title = get_string("kCGWindowName");
let pid = get_number("kCGWindowOwnerPID");
let window_id = get_number("kCGWindowNumber") as u32;
let layer = get_number("kCGWindowLayer");
// Extract bounds dictionary
let bounds = {
let cf_key = CFString::new("kCGWindowBounds");
dict.find(cf_key)
.and_then(|value_ref| {
let bounds_dict = unsafe {
CFDictionary::<CFString, CFTypeRef>::wrap_under_get_rule(*value_ref as *const _)
};
let x = {
let x_key = CFString::new("X");
bounds_dict.find(x_key)
.and_then(|v| {
let cf_number = unsafe { CFNumber::wrap_under_get_rule(*v as *const _) };
cf_number.to_f64()
})
.unwrap_or(0.0)
};
let y = {
let y_key = CFString::new("Y");
bounds_dict.find(y_key)
.and_then(|v| {
let cf_number = unsafe { CFNumber::wrap_under_get_rule(*v as *const _) };
cf_number.to_f64()
})
.unwrap_or(0.0)
};
let width = {
let width_key = CFString::new("Width");
bounds_dict.find(width_key)
.and_then(|v| {
let cf_number = unsafe { CFNumber::wrap_under_get_rule(*v as *const _) };
cf_number.to_f64()
})
.unwrap_or(0.0)
};
let height = {
let height_key = CFString::new("Height");
bounds_dict.find(height_key)
.and_then(|v| {
let cf_number = unsafe { CFNumber::wrap_under_get_rule(*v as *const _) };
cf_number.to_f64()
})
.unwrap_or(0.0)
};
Some(CGRect::new(&CGPoint::new(x, y), &CGSize::new(width, height)))
})
.unwrap_or_else(|| CGRect::new(&CGPoint::new(0.0, 0.0), &CGSize::new(0.0, 0.0)))
};
// Skip windows with zero area
if bounds.size.width > 0.0 && bounds.size.height > 0.0 {
Some(WindowInfo {
app_name,
window_title,
pid,
window_id,
bounds,
layer,
})
} else {
None
}
}
}
/// Get all visible windows that are currently on screen.
pub fn get_visible_windows() -> Vec<WindowInfo> {
let window_list_ref = unsafe {
CGWindowListCopyWindowInfo(
kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements,
0,
)
};
let window_list = unsafe { CFArray::<CFDictionary<CFString, CFTypeRef>>::wrap_under_create_rule(window_list_ref) };
let mut visible_windows = Vec::new();
for i in 0..window_list.len() {
if let Some(window_dict) = window_list.get(i) {
if let Some(window_info) = WindowInfo::from_cf_dict(&window_dict) {
visible_windows.push(window_info);
}
}
}
visible_windows
}
/// Get unique application names that have visible windows on screen.
pub fn get_top_level_visible_apps() -> Vec<String> {
let windows = get_visible_windows();
let mut app_names = HashSet::new();
for window in windows {
let app_name = &window.app_name;
if !app_name.is_empty() && app_name != "Window Server" && app_name != "Dock" && app_name != "Control Center" {
app_names.insert(app_name.clone());
}
}
let mut sorted_apps: Vec<String> = app_names.into_iter().collect();
sorted_apps.sort();
sorted_apps
}
/// Get the frontmost (topmost) window.
pub fn get_frontmost_window() -> Option<WindowInfo> {
let windows = get_visible_windows();
// Filter out system windows and find the one with the highest layer
let user_windows: Vec<_> = windows
.into_iter()
.filter(|w| w.app_name != "Window Server" && w.app_name != "Dock" && w.app_name != "Control Center")
.collect();
user_windows
.into_iter()
.max_by_key(|w| w.layer)
}
/// Get JetBrains IDEs that are currently visible on screen.
/// Returns a list of IDE names that have visible windows.
pub fn get_visible_jetbrains_ides() -> Vec<String> {
let jetbrains_ides = [
"pycharm", "clion", "webstorm", "phpstorm", "rubymine", "datagrip",
"rider", "goland", "appcode", "android-studio", "dataspell", "fleet",
"gateway", "space", "rustrover", "intellij",
];
let visible_apps = get_top_level_visible_apps();
let mut found_ides = Vec::new();
for app_name in visible_apps {
let app_lower = app_name.to_lowercase();
for &ide_name in &jetbrains_ides {
if app_lower.contains(ide_name) {
found_ides.push(ide_name.to_string());
break; // Found match for this app, move to next
}
}
}
found_ides.sort();
found_ides.dedup();
found_ides
}
/// Get the frontmost JetBrains IDE if one is currently focused.
/// Returns the IDE name if a JetBrains IDE is the frontmost window.
pub fn get_frontmost_jetbrains_ide() -> Option<String> {
let jetbrains_ides = [
"pycharm", "clion", "webstorm", "phpstorm", "rubymine", "datagrip",
"rider", "goland", "appcode", "android-studio", "dataspell", "fleet",
"gateway", "space", "rustrover", "intellij",
];
if let Some(frontmost) = get_frontmost_window() {
let app_lower = frontmost.app_name.to_lowercase();
for &ide_name in &jetbrains_ides {
if app_lower.contains(ide_name) {
return Some(ide_name.to_string());
}
}
}
None
}
use macos_active_apps::*;
fn main() {
println!("=== Truly Visible Applications (with windows on screen) ===");
let visible_apps = get_top_level_visible_apps();
println!("Apps with visible windows: {:?}", visible_apps);
println!("Total: {} applications", visible_apps.len());
println!("\n=== JetBrains IDEs Detection ===");
let jetbrains_ides = get_visible_jetbrains_ides();
if jetbrains_ides.is_empty() {
println!("No JetBrains IDEs currently visible");
} else {
println!("Visible JetBrains IDEs: {:?}", jetbrains_ides);
}
if let Some(frontmost_ide) = get_frontmost_jetbrains_ide() {
println!("Frontmost JetBrains IDE: {}", frontmost_ide);
} else {
println!("No JetBrains IDE is currently frontmost");
}
println!("\n=== Frontmost Window ===");
if let Some(frontmost) = get_frontmost_window() {
println!("App: {} (PID: {})", frontmost.app_name, frontmost.pid);
println!("Window: {}", if frontmost.window_title.is_empty() { "[No Title]" } else { &frontmost.window_title });
println!("Position: ({}, {})", frontmost.bounds.origin.x, frontmost.bounds.origin.y);
println!("Size: {} x {}", frontmost.bounds.size.width, frontmost.bounds.size.height);
println!("Window ID: {}, Layer: {}", frontmost.window_id, frontmost.layer);
} else {
println!("No frontmost window found");
}
println!("\n=== All Visible Windows (first 10) ===");
let all_windows = get_visible_windows();
let mut count = 0;
for window in all_windows {
if window.app_name != "Window Server" && window.app_name != "Dock" && window.app_name != "Control Center" {
count += 1;
if count > 10 {
break;
}
let title = if window.window_title.is_empty() { "[No Title]" } else { &window.window_title };
println!("{:2}. {} (PID: {}): {}", count, window.app_name, window.pid, title);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment