Skip to content

Commit

Permalink
Add LuaSkin canaries to hs.uielement.watcher, hs.audiodevice.watcher …
Browse files Browse the repository at this point in the history
…and hs.keycodes
  • Loading branch information
cmsj committed May 1, 2021
1 parent e5c2ced commit da2f41a
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 16 deletions.
1 change: 1 addition & 0 deletions Hammerspoon/HSuicore.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
@property (nonatomic) BOOL running;
@property (nonatomic) pid_t pid;
@property (nonatomic) BOOL watchDestroyed;
@property (nonatomic) LSGCCanary lsCanary;

-(HSuielementWatcher *)initWithElement:(HSuielement *)element callbackRef:(int)callbackRef userdataRef:(int)userdataRef;
-(void)dealloc;
Expand Down
4 changes: 3 additions & 1 deletion Hammerspoon/HSuicore.m
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ -(id)newWatcherAtIndex:(int)callbackRefIndex withUserdataAtIndex:(int)userDataRe
HSuielementWatcher *watcher = [[HSuielementWatcher alloc] initWithElement:self
callbackRef:(int)callbackRef
userdataRef:(int)userDataRef];
watcher.lsCanary = [skin createGCCanary];
return watcher;
}

Expand Down Expand Up @@ -378,10 +379,11 @@ -(NSString *)getSelectedText {

static void watcher_observer_callback(AXObserverRef observer __unused, AXUIElementRef element,
CFStringRef notificationName, void* contextData) {
HSuielementWatcher *watcher = (__bridge HSuielementWatcher *)contextData;
LuaSkin *skin = [LuaSkin sharedWithState:NULL];
[skin checkGCCanary:watcher.lsCanary];
_lua_stackguard_entry(skin.L);

HSuielementWatcher *watcher = (__bridge HSuielementWatcher *)contextData;

[skin pushLuaRef:watcher.refTable ref:watcher.handlerRef]; // Callback function

Expand Down
11 changes: 10 additions & 1 deletion extensions/audiodevice/watcher.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
typedef struct _audiodevice_watcher_t {
int callback;
BOOL running;
LSGCCanary lsCanary;
} audiodevice_watcher;

const AudioObjectPropertySelector watchSelectors[] = {
Expand Down Expand Up @@ -46,11 +47,17 @@ OSStatus audiodevicewatcher_callback(AudioDeviceID deviceID, UInt32 numAddresses

//NSLog(@"%i addresses to check", numAddresses);
LuaSkin *skin = [LuaSkin sharedWithState:NULL];
_lua_stackguard_entry(skin.L);

if (!theWatcher) {
[skin logWarn:@"hs.audiodevice.watcher callback fired, but theWatcher is nil. This is a bug"];
return;
}

if (![skin checkGCCanary:theWatcher->lsCanary]) {
return;
}
_lua_stackguard_entry(skin.L);

if (theWatcher->callback == LUA_NOREF) {
[skin logWarn:@"hs.audiodevice.watcher callback fired, but there is no callback. This is a bug"];
} else {
Expand Down Expand Up @@ -96,6 +103,7 @@ static int audiodevicewatcher_setCallback(lua_State *L) {
memset(theWatcher, 0, sizeof(audiodevice_watcher));
theWatcher->running = NO;
theWatcher->callback = LUA_NOREF;
theWatcher->lsCanary = [skin createGCCanary];
}

theWatcher->callback = [skin luaUnref:refTable ref:theWatcher->callback];
Expand Down Expand Up @@ -215,6 +223,7 @@ static int audiodevicewatcher_gc(lua_State *L) {
if (theWatcher) {
audiodevicewatcher_stop(L);
theWatcher->callback = [skin luaUnref:refTable ref:theWatcher->callback];
[skin destroyGCCanary:&(theWatcher->lsCanary)];
free(theWatcher);
theWatcher = nil;
}
Expand Down
34 changes: 20 additions & 14 deletions extensions/keycodes/internal.m
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ int keycodes_cachemap(lua_State* L) {

@interface MJKeycodesObserver : NSObject
@property int ref;
@property LSGCCanary lsCanary;
@end

@implementation MJKeycodesObserver
Expand All @@ -204,25 +205,24 @@ - (instancetype)init {
return self ;
}

- (void) _inputSourceChanged:(NSNotification*)__unused note {
[self performSelectorOnMainThread:@selector(inputSourceChanged:)
withObject:nil
waitUntilDone:YES];
}

- (void) inputSourceChanged:(NSNotification*)__unused note {
if (self.ref != LUA_NOREF) {
LuaSkin *skin = [LuaSkin sharedWithState:NULL];
_lua_stackguard_entry(skin.L);
[skin pushLuaRef:refTable ref:self.ref];
[skin protectedCallAndError:@"hs.keycodes.inputSourceChanged" nargs:0 nresults:0];
_lua_stackguard_exit(skin.L);
}
dispatch_async(dispatch_get_main_queue(), ^{
if (self.ref != LUA_NOREF) {
LuaSkin *skin = [LuaSkin sharedWithState:NULL];
if (![skin checkGCCanary:self.lsCanary]) {
return;
}
_lua_stackguard_entry(skin.L);
[skin pushLuaRef:refTable ref:self.ref];
[skin protectedCallAndError:@"hs.keycodes.inputSourceChanged" nargs:0 nresults:0];
_lua_stackguard_exit(skin.L);
}
});
}

- (void) start {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_inputSourceChanged:)
selector:@selector(inputSourceChanged:)
name:NSTextInputContextKeyboardSelectionDidChangeNotification
object:nil];
/* This should have made things better, but it seems to cause crashes for some, possibly because the paired removeObserver call is wrong?
Expand Down Expand Up @@ -257,6 +257,7 @@ static int keycodes_newcallback(lua_State* L) {

MJKeycodesObserver* observer = [[MJKeycodesObserver alloc] init];
observer.ref = ref;
observer.lsCanary = [skin createGCCanary];
[observer start];

void** ud = lua_newuserdata(L, sizeof(id));
Expand All @@ -277,6 +278,11 @@ static int keycodes_callback_gc(lua_State* L) {
LuaSkin *skin = [LuaSkin sharedWithState:L];

MJKeycodesObserver* observer = (__bridge_transfer MJKeycodesObserver*)*(void**)luaL_checkudata(L, 1, USERDATA_TAG);

LSGCCanary tmplsCanary = observer.lsCanary;
[skin destroyGCCanary:&tmplsCanary];
observer.lsCanary = tmplsCanary;

[observer stop];

observer.ref = [skin luaUnref:refTable ref:observer.ref];
Expand Down
4 changes: 4 additions & 0 deletions extensions/uielement/watcher.m
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ static int userdata_gc(lua_State* L) {
[skin checkArgs:LS_TUSERDATA, USERDATA_TAG, LS_TBREAK];
HSuielementWatcher *watcher = get_objectFromUserdata(__bridge_transfer HSuielementWatcher, L, 1, USERDATA_TAG);
if (watcher) {
LSGCCanary tmplsCanary = watcher.lsCanary;
[skin destroyGCCanary:&tmplsCanary];
watcher.lsCanary = tmplsCanary;

watcher.selfRefCount--;
if (watcher.selfRefCount == 0) {
[watcher stop];
Expand Down

0 comments on commit da2f41a

Please sign in to comment.