frewsxcv / rust-dark-light

Rust crate to detect if dark mode or light mode is enabled
https://crates.io/crates/dark-light
81 stars 15 forks source link

Rewrite macOS integration to not shell out to `defaults` #2

Closed frewsxcv closed 2 years ago

frewsxcv commented 3 years ago

https://github.com/frewsxcv/rust-dark-light/blob/dbbf35b7ce9916563a5af01e5b9a3d8622cb85cc/src/macos.rs#L3-L14

Instead of using the command line, we should call the API directly:

[[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
felipesere commented 2 years ago

I think you could use this to access the value directly? https://docs.rs/cacao/latest/cacao/defaults/struct.UserDefaults.html Not sure if it’s a pretty big dependency to pull in though…

ryanmcgrath commented 2 years ago

Stumbled my way here via Reddit. You should actually be able to check this without ever touching UserDefaults (and thus avoid cacao, though you're welcome to depend on it if you so desire). It's also worth noting that macOS technically has more than just dark vs light, due to high contrast variants - but for the purposes of your lib you could probably skim it all down.

You might want to take a look at how I shimmed dynamic custom colors for macOS - just swap out the cacao-y bits (the ivars, etc) and so on. You'll need objc as a crate and probably link Foundation in a build.rs, and you'll need a bit of Objective-C to construct the NSArray. There's... gonna be some unsafe calls in here, but as far as the underlying APIs go it should cover all the cases.

https://github.com/ryanmcgrath/cacao/blob/01d12396ef7a047a94949a528f8b7d70e88a6905/src/color/macos_dynamic_color.rs#L30-L77

extern "C" {
    static NSAppearanceNameAqua: id;
    static NSAppearanceNameAccessibilityHighContrastAqua: id;
    static NSAppearanceNameDarkAqua: id;
    static NSAppearanceNameAccessibilityHighContrastDarkAqua: id;
}

fn get_effective_color(this: &Object) -> id {
    if os::is_minimum_semversion(10, 14, 0) {
        unsafe {
            let mut appearance: id = msg_send![class!(NSAppearance), currentAppearance];
            if appearance == nil {
                appearance = msg_send![class!(NSApp), effectiveAppearance];
            }

            let names = NSArray::new(&[
                NSAppearanceNameAqua,
                NSAppearanceNameAccessibilityHighContrastAqua,
                NSAppearanceNameDarkAqua,
                NSAppearanceNameAccessibilityHighContrastDarkAqua
            ]);

            let style: id = msg_send![appearance, bestMatchFromAppearancesWithNames:&*names];

            if style == NSAppearanceNameDarkAqua {
                return *this.get_ivar(AQUA_DARK_COLOR_NORMAL_CONTRAST);
            }

            if style == NSAppearanceNameAccessibilityHighContrastAqua {
                return *this.get_ivar(AQUA_LIGHT_COLOR_HIGH_CONTRAST);
            }

            if style == NSAppearanceNameAccessibilityHighContrastDarkAqua {
                return *this.get_ivar(AQUA_DARK_COLOR_HIGH_CONTRAST);
            }
        }
    }

    unsafe {
        return *this.get_ivar(AQUA_LIGHT_COLOR_NORMAL_CONTRAST);
    }
}
frewsxcv commented 2 years ago

@ryanmcgrath Thank you! I just opened https://github.com/frewsxcv/rust-dark-light/pull/9 and if you ever have a moment would really appreciate a glance over it