Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check when WebKit context is available in NW.js

When executed in Node context (node-main),

setTimeout(function () {
    console.log(nw);
}, 20);

throws

nw is not defined

because WebKit context is not ready (right from the start window is unavailable in NW.js <= 0.12, window.nw in NW.js >= 0.13). And

setTimeout(function () {
    console.log(nw);
}, 200);

works just fine but setTimeout looks like a hack, setting it to safe delay value may cause undesirable lag.

How can the availability of WebKit context and nw be checked from Node context? Is there a reasonable way, like an event that could be handled?

like image 818
Estus Flask Avatar asked Apr 23 '16 22:04

Estus Flask


3 Answers

The following achieves the same thing but does it the other way around.

In your html file:

<body onload="process.mainModule.exports.init()">

In your node-main JS file:

exports.init = function() { console.log(nw); }

Here, init function is only called when Webkit context/DOM is available.

like image 119
Rahat Mahbub Avatar answered Nov 02 '22 04:11

Rahat Mahbub


You could use pollit :) ...

var pit = require("pollit");
foo = function(data) {
  console.log(nw);
};
pit.nw('nw', foo);    

I've tested it and it works for me :). This modularizes the solution that I give near the end of this.

The nw object does not exist until webkit is up and running ie the browser window has been created. This happens after Node starts up which is why you're getting this error. To use the nw api you either create events that can be listened to or call global functions the former being preferable. The following code will demonstrate both and should give you a good idea of how Node and WebKit are interfacing with each other.

This example creates a Window, opens devtools and allows you to toggle the screen. It also displays the mouse location in the console. It also demonstrates how to send events using the DOM ie body.onclick() and attaching events from within Node ie we're going to catch minimize events and write them to the console.

For this to work you need to be using the SDK version of NW. This is my package.json

{
  "name": "hello",
  "node-main": "index.js",
  "main": "index.html",
  "window": {
    "toolbar": true,
    "width": 800,
    "height": 600
  },
  "dependencies" : {
    "robotjs" : "*",
    "markdown" : "*"
  }
}

The two files you need are index.html

<!DOCTYPE html>
<html>
  <head>
    <script>
      var win = nw.Window.get();
      global.win = win;
      global.console = console;
      global.main(nw);
      global.mouse();
      var markdown = require('markdown').markdown;
      document.write(markdown.toHTML("-->Click between the arrows to toggle full screen<---"));
    </script>
  </head>
  <body onclick="global.mouse();">
  </body>
</html>

and index.js.

var robot = require("robotjs");

global.mouse = function() {
  var mouse = robot.getMousePos();
  console.log("Mouse is at x:" + mouse.x + " y:" + mouse.y);
  global.win.toggleFullscreen();
}

global.main = function(nw_passed_in) {
  global.win.showDevTools();
  console.log("Starting main");
  console.log(nw_passed_in);
  console.log(nw);
  global.win.on('minimize', function() {
    console.log('n: Window is minimized from Node');
  });
}

When running this I used

nwjs --enable-logging --remote-debugging-port=1729  ./

You can then open up the browser using

http://localhost:1729/

for debugging if needed.

If you want to do something as soon as the nw object exists you can poll it. I'd use eventEmitter, if you don't want to use event emitter you can just as easily wrap this in a function and call it recursively. The following will display how many milliseconds it took before the nw object was setup. On my system this ranged between 43 - 48 milliseconds. Using a recursive function was no different. If you add this to the code above you'll see everything logged to the console.

var start = new Date().getTime();
var events = require('events');
var e = new events.EventEmitter();

var stop = 0;
e.on('foo', function() { 
if(typeof nw === 'undefined') {
  setTimeout(function () {
    e.emit('is_nw_defined');
  }, 1); 
 }   
 else {
   if(stop === 0) {
     stop = new Date().getTime();
   }   
   setTimeout(function () {
     console.log(stop - start);
     console.log(nw);
     e.emit('is_nw_defined');
   }, 2000);
 }   
});
e.emit('is_nw_defined');
like image 2
Harry Avatar answered Nov 02 '22 02:11

Harry


Solution 1:

You can use onload, see reference.

main.js:

var gui = require("nw.gui"),
    win = gui.Window.get();

onload = function() {
    console.log("loaded");
    console.log(win.nw);
};

index.html:

<!DOCTYPE html>
<html>
    <head>
        <script type="text/javascript" src="main.js"></script>
    </head>
    <body></body>
</html>

package.json:

{
  "name": "Freebox",
  "main": "index.html"
}

Solution 2:

(To prevent issue, but it is not necessary).

var gui = require("nw.gui"),
    win = gui.Window.get();

onload = function() {
    console.log("loaded");
    var a = function () {
        if (!win.nw) return setTimeout(a, 10);
        console.log(win.nw);
    };
};
like image 1
Sky Voyager Avatar answered Nov 02 '22 04:11

Sky Voyager