HackPlan / quark-shell-mac

Quark Shell for Mac helps web developers to create native-like Mac menubar app using HTML and JavaScript without writing any native code.
MIT License
910 stars 42 forks source link

mw.emit() bug? #17

Closed acketon closed 9 years ago

acketon commented 10 years ago

I was testing the mw.on() and mw.emit() functions. I wanted the new window to send a message back to the main menubar window and the main window to send a message back to the new window. I was going to use this to send data to the new window after it is opened.

The first message works good, just like your example. if I do this:

mw.on("TestMessage", function(message) {
        console.log(message)
        mw.emit("replymessage", "I can't Dave")
})

mw.emit("replymessage", "I can't Dave"); does not work unless I put it in a setTimeout of about half a second... Then it works.

But after that I ran into a problem. If I close the New Window and then reopen it and run everything a second time, I get an error in the main window when trying to call mw.emit("replymessage", "I can't Dave") a second time. I removed the setTimeout stuff and just manually ran mw.emit() in the console and it also gave the error so it seems to be that mw.emit() can't be called to send a message to the new window anytime AFTER the first time the window is opened and closed.

Error: TypeError: 'undefined' is not an object (evaluating 'func.apply')
xcode console error: 
2014-09-02 23:50:06.252 menubar-webkit[72917:303] JavaScript console: undefined:1: TypeError: 'undefined' is not an object (evaluating 'func.apply')
2014-09-02 23:50:06.253 menubar-webkit[72917:303] -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x608000437ac0

Does that description make sense?

acketon commented 10 years ago

I think I figured out a way around this... maybe I was just using it improperly before.

In the new window I send the main window a timestamp, then listen for a response named with that timestamp like this:

var timestamp = Date.now();
mw.emit("addswatchwindowready", timestamp);
mw.on(timestamp, function(message) {
    console.log("message recieved");
    console.log(message)
});

and in my main window something like this:

mw.on("addswatchwindowready", function(timestamp) {
    console.log(timestamp);
    setTimeout(function(){
        mw.emit(timestamp, JSON.stringify(myobjecttosend));
    },500);
});

That looks to be working good, if a bit weird. Could the open window function have a callback or "loaded" event sent back to the opener window instead? That might be a better way of knowing when the window is open.

xhacker commented 10 years ago

Got your point. mw.on() and mw.emit() are still elementary, I’m working on them.

codewise-nicolas commented 9 years ago

I too ran into the problem with using the emit/on with the new window issue.

Ive narrowed the problem down to the way the new window is spawned. From my understanding of the code, every time the mw.newWindow is called, a whole new webviewcontroller is instantiated. This causes the hooks that may have been previously instantiated to still be in memory somewhere but not accessible, leading to the undefined error and no new hooks working.

I see two possible solutions a) Properly un-hook the event listeners when the window is closed/destoryed b) Dont create a totally new instance of the new window when mw.newWindow is called, simply re-use the old one.

Im trying a few things and well see if i can come up with a proper solution.

xhacker commented 9 years ago

@codewise-nicolas: Actually we still want to implement #18 to allow multiple new windows.

codewise-nicolas commented 9 years ago

Fixed part of the problem, it was that the subscribeMessage() call was incorrectly setting up the messageSubscribers dictionary with an NSArray (which you cant add objects too after the fact). This meant that the old/closed windows registered subscriber was the only one being added and called. When a new window was spawned, it tried to register the same callback name but it was not getting stored. This is why acketon's "solution" worked, it would always create a NEW event handler with a unique name (the time).

Changed the code so that it creates a NSMutableArray instead. Works great. Fix: https://gist.github.com/codewise-nicolas/95786da9363292743ebf

There is still a slight problem that when a window is closed, there is still subscribers in the array - so those need to be removed when the window is closed. Is there any property of WebScriptObject we can look into to determine if the window/webview is still available ?

xhacker commented 9 years ago

Hi @acketon, can you confirm that this issue was fixed?