macos_window_toolkit 1.8.4 copy "macos_window_toolkit: ^1.8.4" to clipboard
macos_window_toolkit: ^1.8.4 copied to clipboard

PlatformmacOS

Flutter plugin for macOS window management and application discovery - retrieve window info, monitor permissions, discover installed apps with type-safe APIs.

macOS Window Toolkit #

pub package License: MIT

A Flutter plugin for macOS window management, screen capture, and application discovery.

Features #

  • 🪟 Window Management - Get, search, filter, close, and focus windows
  • 📸 Screen Capture - Capture windows with ScreenCaptureKit or legacy methods
  • 📱 App Discovery - Find and manage installed applications
  • 🔐 Permission Management - Handle screen recording and accessibility permissions
  • 🎯 Process Control - Terminate applications and manage process trees
  • ⚡️ Real-time Monitoring - Monitor permission changes with streams

Installation #

dependencies:
  macos_window_toolkit: ^1.8.4

Setup (Required) #

1. Disable App Sandbox #

Edit macos/Runner/DebugProfile.entitlements and macos/Runner/Release.entitlements:

<key>com.apple.security.app-sandbox</key>
<false/>
<key>com.apple.security.automation.apple-events</key>
<true/>

2. Request Permissions at Runtime #

final toolkit = MacosWindowToolkit();

// Request screen recording permission (for window names and capture)
await toolkit.requestScreenRecordingPermission();

// Request accessibility permission (for window control and process management)
await toolkit.requestAccessibilityPermission();

Quick Start #

import 'package:macos_window_toolkit/macos_window_toolkit.dart';

final toolkit = MacosWindowToolkit();

// Get all windows
final windows = await toolkit.getAllWindows();
for (final window in windows) {
  print('${window.name} - ${window.ownerName}');
}

// Search windows
final chromeWindows = await toolkit.getWindowsByOwnerName('Chrome');

// Close a window
final result = await toolkit.closeWindow(windowId);

// Capture a window
final capture = await toolkit.captureWindow(windowId);
if (capture case CaptureSuccess(imageData: final data)) {
  // Save or display image data
}

// Find installed apps
final apps = await toolkit.getAllInstalledApplications();
if (apps case ApplicationSuccess(applications: final appList)) {
  print('Found ${appList.length} apps');
}

API Reference #

Window Management (11 methods) #

Method Description
getAllWindows() Get all open windows
getWindowsByName(String name) Search windows by title
getWindowsByOwnerName(String owner) Search by app name
getWindowById(int id) Find window by ID
getWindowsByProcessId(int pid) Find windows by process
getWindowsAdvanced({...}) Advanced filtering (14 parameters)
isWindowAlive(int id) Check if window exists
isWindowFullScreen(int id) Check fullscreen state across Spaces (requires Screen Recording)
closeWindow(int id) Close a window, including windows on other Spaces (requires Accessibility)
focusWindow(int id) Focus/bring window to front (requires Accessibility)
getScrollInfo(int id) Get scroll position (requires Accessibility)

Screen Capture (2 methods) #

Method Description
captureWindow(int id, {...}) Capture window using ScreenCaptureKit (macOS 14.0+). Transparent borders are automatically cropped. Supports titlebar exclusion, resize, custom crop, and crop size control.
getCapturableWindows() List capturable windows using ScreenCaptureKit (macOS 12.3+)

Permission Management (10 methods) #

Method Description
hasScreenRecordingPermission() Check screen recording permission
requestScreenRecordingPermission() Request screen recording permission
openScreenRecordingSettings() Open system settings
hasAccessibilityPermission() Check accessibility permission
requestAccessibilityPermission() Request accessibility permission
openAccessibilitySettings() Open system settings
startPermissionWatching({interval, emitOnlyChanges}) Start periodic permission monitoring
stopPermissionWatching() Stop permission monitoring
permissionStream Stream of permission status changes
isPermissionWatching Whether monitoring is currently active

Application Management (5 methods) #

Method Description
getAllInstalledApplications() Get all installed apps
getApplicationByName(String name) Search apps by name
openAppStoreSearch(String term) Open App Store search
terminateApplicationByPID(int pid) Terminate app (requires Accessibility)
terminateApplicationTree(int pid) Terminate app and children (requires Accessibility)

System Info (4 methods) #

Method Description
getMacOSVersionInfo() Get macOS version and capabilities
getChildProcesses(int pid) Get child process IDs
getScreenScaleFactor() Get main screen's Retina scale (1.0, 2.0, etc.)
getAllScreensInfo() Get all screens info (size, pixels, scale)

Permission Requirements #

Feature Screen Recording Accessibility
Get window list
Get window names
Window capture
Fullscreen detection
Close/focus windows
Terminate processes
Window role/subrole
Get scroll info

Data Models #

MacosWindowInfo #

class MacosWindowInfo {
  final int windowId;
  final String name;           // Empty if no screen recording permission
  final String ownerName;
  final double x, y, width, height;
  final int layer;
  final bool isOnScreen;
  final int processId;
  final String? role;          // Requires accessibility permission
  final String? subrole;       // Requires accessibility permission
}

MacosApplicationInfo #

class MacosApplicationInfo {
  final String name;
  final String bundleId;
  final String version;
  final String path;
  final String iconPath;
}

MacosScreenInfo #

class MacosScreenInfo {
  final int index;
  final bool isMain;
  final double scaleFactor;
  final ScreenRect frame;           // Full screen frame
  final ScreenRect visibleFrame;    // Excluding menu bar/dock
  final int pixelWidth;
  final int pixelHeight;
}

class ScreenRect {
  final double x, y, width, height;
}

Examples #

Permission Monitoring with Stream #

toolkit.startPermissionWatching(
  interval: Duration(seconds: 2),
  emitOnlyChanges: true,
);

toolkit.permissionStream.listen((status) {
  print('Screen Recording: ${status.screenRecording}');
  print('Accessibility: ${status.accessibility}');
  if (status.allPermissionsGranted) {
    print('All ready!');
  }
});

Advanced Window Filtering #

final windows = await toolkit.getWindowsAdvanced(
  ownerName: 'Chrome',
  ownerNameCaseSensitive: false,
  isOnScreen: true,
  width: 800,  // Exact width
);

Get Screen Information #

final screens = await toolkit.getAllScreensInfo();
for (final screen in screens) {
  print('Screen ${screen.index}: ${screen.isMain ? "(Main)" : ""}');
  print('  Scale: ${screen.scaleFactor}x');
  print('  Size: ${screen.frame.width} x ${screen.frame.height}');
  print('  Pixels: ${screen.pixelWidth} x ${screen.pixelHeight}');
}

Fullscreen Detection #

// Accurate across all Spaces (uses SCShareableContent, not CGWindowList)
final isFullScreen = await toolkit.isWindowFullScreen(windowId);
if (isFullScreen) {
  print('Window is in fullscreen mode');
}

Window Capture with Crop #

// Basic capture (transparent borders are auto-cropped)
final capture = await toolkit.captureWindow(windowId);

// Exclude titlebar
final capture = await toolkit.captureWindow(
  windowId,
  excludeTitlebar: true,
  customTitlebarHeight: 44,  // optional, default 28pt
);

// Resize output
final capture = await toolkit.captureWindow(
  windowId,
  targetWidth: 1920,
  targetHeight: 1080,
  preserveAspectRatio: true,  // fills extra space with black
);

// Center crop (crops to given size from the center of the image)
final capture = await toolkit.captureWindow(
  windowId,
  cropContentWidth: 1680,
  cropContentHeight: 945,
);

// Rect crop (crops to an exact rectangle)
final capture = await toolkit.captureWindow(
  windowId,
  cropX: 100,
  cropY: 50,
  cropWidth: 800,
  cropHeight: 600,
);

// Return actual content size after transparent border crop (no stretching)
// Default (true): transparent borders removed, then image stretched back to window frame size
// false: returns the naturally cropped content size as-is
final capture = await toolkit.captureWindow(
  windowId,
  resizeCroppedToWindowSize: false,
);

if (capture case CaptureSuccess(imageData: final data)) {
  // Use image data
}

Get Scroll Position #

final result = await toolkit.getScrollInfo(windowId);
switch (result) {
  case ScrollSuccess(scrollInfo: final info):
    print('Vertical: ${info.verticalPosition}');  // 0.0 (top) ~ 1.0 (bottom)
  case ScrollFailure(:final reason, :final message):
    switch (reason) {
      case ScrollFailureReason.windowNotFound:
        print('Window no longer exists');
      case ScrollFailureReason.windowNotAccessible:
        // Window exists but AX API cannot access it
        // Common cause: window is on a different Space
        print('Window not accessible — switch to the Space where it is located');
      case ScrollFailureReason.accessibilityPermissionDenied:
        await toolkit.openAccessibilitySettings();
      case ScrollFailureReason.noScrollableContent:
        print('No scrollable content');
      case ScrollFailureReason.unknown:
        print('Failed: $message');
    }
}

Error Handling #

try {
  final windows = await toolkit.getAllWindows();
} on PlatformException catch (e) {
  switch (e.code) {
    case 'SCREEN_RECORDING_PERMISSION_DENIED':
      await toolkit.openScreenRecordingSettings();
    case 'ACCESSIBILITY_PERMISSION_DENIED':
      await toolkit.openAccessibilitySettings();
  }
}

Close Window Error Handling #

final result = await toolkit.closeWindow(windowId);
switch (result) {
  case OperationSuccess():
    print('Window closed');
  case OperationFailure(:final code, :final message):
    switch (code) {
      case 'WINDOW_NOT_FOUND':
        print('Window no longer exists');
      case 'WINDOW_NOT_ACCESSIBLE':
        // Window exists but AX API cannot access it
        print('Window not accessible: $message');
      case 'SPACE_SWITCH_API_UNAVAILABLE':
        // Window is on a different Space but the private CGS APIs
        // required to switch Spaces are not available on this macOS version
        print('Cannot switch Space to reach window: $message');
      case 'ACCESSIBILITY_PERMISSION_DENIED':
        await toolkit.openAccessibilitySettings();
    }
}

Requirements #

  • macOS 10.15+ (14.0+ required for window capture)
  • Flutter 3.10.0+
  • Dart 3.0.0+
  • App Sandbox must be disabled

App Store Distribution #

⚠️ Not recommended for App Store distribution due to sandbox requirements. This plugin requires system-level access that conflicts with App Store sandboxing policies. Consider:

  • Distributing outside the App Store
  • Requesting special entitlements from Apple (rarely approved)

Example App #

cd example/
flutter run -d macos

Documentation #

License #

MIT License - see LICENSE file for details.


Made with ❤️ for the Flutter community

2
likes
150
points
692
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter plugin for macOS window management and application discovery - retrieve window info, monitor permissions, discover installed apps with type-safe APIs.

Repository (GitHub)
View/report issues

Topics

#macos #window-management #application-discovery #screenshots #flutter-macos

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on macos_window_toolkit

Packages that implement macos_window_toolkit