1

I'm creating an extension for Firefox (SDK Add-on) in which I'll need to detect screensaver and lock-screen events so that I can set a user's availability status in a web-app.

I've managed to do this already for Windows and now need to port to OS X. For the Windows version, I was using calls to native API to find out if screen was locked, etc. Is there a similar way of getting OS information from a Firefox extension on OS X? I've tried Googling this and haven't found a solid answer - any help appreciated!

nmaier
  • 32,336
  • 5
  • 63
  • 78
BeneGal
  • 180
  • 1
  • 11

1 Answers1

2

On OSX you can query a locked screen/screensaver using CGSessionCopyCurrentDictionary and looking for the presence and value of the "CGSSessionScreenIsLocked" key.

This is platform API, so one will have to use js-ctypes again and write a bunch of code to get that working.

I did get it working: The following code is a working example you can run in a privileged Scratchpad. To get a privileged one, open a pad for e.g. about:newtab.

Components.utils.import("resource://gre/modules/ctypes.jsm");

var CoreFoundation = new (function() {
    this.CFNumberRef = ctypes.voidptr_t;
    this.CFStringRef = ctypes.voidptr_t;
    this.CFDictionaryRef = ctypes.voidptr_t;

    var lib = ctypes.open("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation");
    this.CFRelease = lib.declare(
        "CFRelease",
        ctypes.default_abi,
        ctypes.void_t,
        ctypes.voidptr_t);

    var CFStringCreateWithCharacters = lib.declare(
        "CFStringCreateWithCharacters",
        ctypes.default_abi,
        this.CFStringRef,
        ctypes.voidptr_t,
        ctypes.jschar.ptr,
        ctypes.int32_t);
    this.CFStringCreateWithCharacters = function(str) {
        var rv = CFStringCreateWithCharacters(null, str, str.length);
        if (!rv || rv.isNull()) {
            return null;
        }
        return ctypes.CDataFinalizer(rv, this.CFRelease);
    };


    var CFDictionaryGetValue = lib.declare(
        "CFDictionaryGetValue",
        ctypes.default_abi,
        this.CFNumberRef,
        this.CFDictionaryRef,
        this.CFStringRef);
    this.CFDictionaryGetInt = function(dict, str) {
        var rv = CFDictionaryGetValue(dict, this.CFStringCreateWithCharacters(str));
        if (!rv || rv.isNull()) {
            return null;
        };
        return this.CFNumberGetValue(rv);
    };

    var CFNumberGetValue = lib.declare(
        "CFNumberGetValue",
        ctypes.default_abi,
        ctypes.bool,
        this.CFNumberRef,
        ctypes.int32_t,
        ctypes.int32_t.ptr);
    this.CFNumberGetValue = function(num) {
        var rv = new ctypes.int32_t();
        CFNumberGetValue(num, 3, rv.address());
        console.log("CFNumberGetValue", rv, rv.value);
        return rv.value;
    };
    this.close = function() {
        lib.close();
    };
})();
var ApplicationServices = new (function() {
    var lib = ctypes.open("/System/Library/Frameworks/ApplicationServices.framework/ApplicationServices");

    var CGSessionCopyCurrentDictionary = lib.declare(
        "CGSessionCopyCurrentDictionary",
        ctypes.default_abi,
        CoreFoundation.CFDictionaryRef);
    this.CGSessionCopyCurrentDictionary = function() {
        var rv = CGSessionCopyCurrentDictionary();
        if (!rv || rv.isNull()) {
            return null;
        }
        return ctypes.CDataFinalizer(rv, CoreFoundation.CFRelease);
    };

    this.close = function() {
        lib.close();
    };
})();

setInterval(function() {
    var dict = ApplicationServices.CGSessionCopyCurrentDictionary();
    if (dict) {
        var locked = CoreFoundation.CFDictionaryGetInt(dict, "CGSSessionScreenIsLocked");
        console.log("rv", locked);
        if (locked) {
            // do something;
        }
    }
}, 500);
Community
  • 1
  • 1
nmaier
  • 32,336
  • 5
  • 63
  • 78
  • Thanks so much for your suggestions. I have seen this working in Scratchpad - however, the exact same code running inside my add-on gives the following error: "ctypes.CDataFinalizer is not a function" Any ideas as to what could be causing this? – BeneGal Dec 03 '13 at 15:46
  • Oh, no I meant the exact code you provided above. Was hoping maybe it was something you might have come across previously. Will continue to investigate. – BeneGal Dec 03 '13 at 16:26
  • Well, without you providing a self-contained, reproducible example showing the error, I won't be able to help. – nmaier Dec 03 '13 at 16:33
  • Holy sheesh I just wrote my own version and then found yours. Dang so awesome man. Mine is a little different, I think mine is more right!! :P I don't use the yucky finalizer, no guarntee for call :P i do manual, and its a boolean. but man you did it differently and now that i did mine, looking at yours teaches me so much, thanks so much for this man!! heres mine: https://gist.github.com/Noitidart/ff19ae88500a649c1ef9 – Noitidart Dec 17 '14 at 18:46
  • 1
    btw `CGSessionScreenLocked` only is 1 if the lock screen setting is set to true. if its not set we have to use px or something to test if screensaver is on. – Noitidart Dec 17 '14 at 18:50
  • you need to `CFRelease` the `this.CFStringCreateWithCharacters(str)` :P allso your return type on CFDictionaryGetValue` is very specific, but you dont have to mess with casting nice :P – Noitidart Dec 17 '14 at 19:20