mkiol / GNotifier

Thunderbird add-on that replaces built-in notifications with the OS native notifications
https://addons.mozilla.org/thunderbird/addon/gnotifier/
GNU General Public License v3.0
164 stars 25 forks source link

Mac ctypes - very nice work! #40

Closed Noitidart closed 9 years ago

Noitidart commented 9 years ago

Your mac ctypes of objective c is so awesome. I've been struggling a lot with it. I couldn't find any open source examples of it but finally found your repo, its excellent and I can learn a TON from it!! :) Thanks for it!

Just trying my luck here: Would you have time to chat about objc ctypes? I'm trying to get setApplicationIcon: https://bugzilla.mozilla.org/show_bug.cgi?id=1108246#c2

mkiol commented 9 years ago

I glad you find ctypes awesome :-) True that, they are quite useful and powerful tool.

Regarding objective c, the code is not mine. Everything was done by @kennydude. He is the author of all "OSX branch", so probably he will be the most appropriate person to ask about details.

Noitidart commented 9 years ago

Thanks @mkiol for your fast reply!

I had a blast with ctypes I got it working in windows and linux's (https://github.com/Noitidart/Profilist/issues/18#issuecomment-46795390) but mac drives me nuts haha!

Noitidart commented 9 years ago

@kennydude

Im working on the setApplicationIcon thing for my addon.

And im trying to help this user on stackoverflow: http://stackoverflow.com/questions/27377686/firefox-extension-addon-detect-workspace-locked

So I'm trying to convert this:

http://mxr.mozilla.org/chromium/source/src/chrome/browser/idle_mac.mm#28

28 - (id)init {
29   if ((self = [super init])) {
30     NSDistributedNotificationCenter* distCenter =
31           [NSDistributedNotificationCenter defaultCenter];
32     [distCenter addObserver:self
33                    selector:@selector(onScreenSaverStarted:)
34                        name:@"com.apple.screensaver.didstart"
35                      object:nil];
36     [distCenter addObserver:self
37                    selector:@selector(onScreenSaverStopped:)
38                        name:@"com.apple.screensaver.didstop"
39                      object:nil];
40     [distCenter addObserver:self
41                    selector:@selector(onScreenLocked:)
42                        name:@"com.apple.screenIsLocked"
43                      object:nil];
44     [distCenter addObserver:self
45                    selector:@selector(onScreenUnlocked:)
46                        name:@"com.apple.screenIsUnlocked"
47                      object:nil];
48   }
49   return self;
50 }

So far I got this:

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

let objc = ctypes.open(ctypes.libraryName("objc"));

let id = ctypes.voidptr_t;
let SEL = ctypes.voidptr_t;

let objc_getClass = objc.declare("objc_getClass",
                                 ctypes.default_abi,
                                 id,
                                 ctypes.char.ptr);

let sel_registerName = objc.declare("sel_registerName",
                                    ctypes.default_abi,
                                    SEL,
                                    ctypes.char.ptr);

let objc_msgSend = objc.declare("objc_msgSend",
                                ctypes.default_abi,
                                id,
                                id,
                                SEL,
                                "...");

let NSDistributedNotificationCenter = objc_getClass("NSDistributedNotificationCenter");
let defaultCenter = sel_registerName("defaultCenter");
let nC = objc_msgSend(NSDistributedNotificationCenter, defaultCenter);

let addObserver = sel_registerName("addObserver:selector:name:object:");
let removeObserver = sel_registerName("removeObserver:name:object:");

lol please help me help this guy on stackvoerflow i think ill learn a lot in the process :D

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDistributedNotificationCenter_Class/index.html

Noitidart commented 9 years ago

I got it! It works! Long live open source! Thanks for it @mkiol and @kennydude . But I'm not sure if the code is absolutely correct. @kennydude may you please review this code of mine here. It does addObserver of a callback to trigger when the screensaver turns on:

For instance I'm not sure if I'm not sure which is the right spot for me to execute objc_msgSend(pool, release); after I finish alloc and init of delegateInstance_onScreenSaverStarted. Is it ok to run right after the msgSend? Or maybe shutdown when I call removeObserver? Or after I do addObserver?

Thanks, can copy this code paste to scratchpad and run it will add the observer, then wait till screensaver triggers, then move mouse and u'll see the msg in browser console. To remove observer, blank the same scratchpad you ran the code from and type removeObsAndClose() then run.

Cu.import('resource://gre/modules/ctypes.jsm');
var objc = ctypes.open(ctypes.libraryName('objc'));

// types
var id = ctypes.voidptr_t;
var objc_selector = new ctypes.StructType('objc_selector');
var SEL = objc_selector.ptr;
var BOOL = ctypes.signed_char;
var IMP = ctypes.voidptr_t;

// contstants
var nil = ctypes.voidptr_t(0);

// common functions
var objc_getClass = objc.declare('objc_getClass', ctypes.default_abi, id, ctypes.char.ptr);
var sel_registerName = objc.declare('sel_registerName', ctypes.default_abi, SEL, ctypes.char.ptr);
var objc_msgSend = objc.declare('objc_msgSend', ctypes.default_abi, id, id, SEL, '...');

// common selectors
var alloc = sel_registerName('alloc');
var init = sel_registerName('init');
var release = sel_registerName('release');

// notificationName_**** = [[NSString alloc] initWithUTF8String: 'com.apple.****'];
var NSString = objc_getClass('NSString');
var initWithUTF8String = sel_registerName('initWithUTF8String:');

// NSDistCent = [NSDistributedNotificationCenter defaultCenter];
var NSDistributedNotificationCenter = objc_getClass('NSDistributedNotificationCenter');
var defaultCenter = sel_registerName('defaultCenter');
var NSDistCent = objc_msgSend(NSDistributedNotificationCenter, defaultCenter);

//create notificationObserver's
var notificationSelector_onScreenSaverStarted = sel_registerName('onScreenSaverStarted:');
var notificationName_onScreenSaverStarted = objc_msgSend(objc_msgSend(NSString, alloc), initWithUTF8String, ctypes.char.array()('com.apple.screensaver.didstart'));

// NSAutoPool = [[NSAutoreleasePool alloc] init]
var NSAutoreleasePool = objc_getClass('NSAutoreleasePool');
var pool = objc_msgSend(objc_msgSend(NSAutoreleasePool, alloc), init);

var objc_allocateClassPair = objc.declare('objc_allocateClassPair', ctypes.default_abi, id, id, ctypes.char.ptr, ctypes.size_t);

var NSObject = objc_getClass('NSObject');
var delegate_onScreenSaverStarted = objc_allocateClassPair(NSObject, 'onScreenSaverStarted', 0);

var class_addMethod = objc.declare('class_addMethod', ctypes.default_abi, BOOL, id, SEL, IMP, ctypes.char.ptr);
//
var ftype_onScreenSaverStarted = ctypes.FunctionType(ctypes.default_abi, ctypes.void_t, [])

function jsCallback_onScreenSaverStarted(self, sel) {
    console.log('TRIGGERD: onScreenSaverStarted');
}

var callback_onScreenSaverStarted = ftype_onScreenSaverStarted.ptr(jsCallback_onScreenSaverStarted);
//
var rez_class_addMethod = class_addMethod(delegate_onScreenSaverStarted, notificationSelector_onScreenSaverStarted, callback_onScreenSaverStarted, 'onScreenSaverStarted:');
console.info('rez_class_addMethod:', rez_class_addMethod, rez_class_addMethod.toString(), uneval(rez_class_addMethod));

var objc_registerClassPair = objc.declare('objc_registerClassPair', ctypes.default_abi, id, id);
objc_registerClassPair(delegate_onScreenSaverStarted);

var delegateInstance_onScreenSaverStarted = objc_msgSend(objc_msgSend(delegate_onScreenSaverStarted, alloc), init);

objc_msgSend(pool, release); //maybe don't release pool yet?
//end - onScreenSaverStarted

// [NSDistCent addObserver:selector:name:object: ***, ***, notificationName_****, nil] // copied block: `// [NSApp setApplicationIconImage: icon]`
var addObserver = sel_registerName('addObserver:selector:name:object:')
var rez_addObserver = objc_msgSend(NSDistCent, addObserver, delegateInstance_onScreenSaverStarted, notificationSelector_onScreenSaverStarted, notificationName_onScreenSaverStarted, nil); // addObserver returns void so no need for `var rez_addObserver = `

function removeObsAndClose() {
  // [NSDistCent removeObserver:name:object: notificationName_****, nil] // copied block: `// [NSApp setApplicationIconImage: icon]`
  var removeObserver = sel_registerName('removeObserver:name:object:')
  var rez_removeObserver = objc_msgSend(NSDistCent, removeObserver, delegateInstance_onScreenSaverStarted, notificationName_onScreenSaverStarted, nil); // removeObserver returns void

  // [notificationName_**** release]
  objc_msgSend(notificationName_onScreenSaverStarted, release);

  objc.close();
}
Noitidart commented 9 years ago

Thanks very much @mkiol for leaving this open. Closing stuff hurts feelings haha but I understand. Please close this whenever you wish. :)

mkiol commented 9 years ago

so, please, don't take this personal.. I'm closing this issue :-)

Noitidart commented 9 years ago

haha thanks man you're real nice guy :D thanks also for trying to get kenny's attention to my topic :)