Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Communicate between two windows #991

Closed
iamdriz opened this issue Jan 9, 2015 · 20 comments
Closed

Communicate between two windows #991

iamdriz opened this issue Jan 9, 2015 · 20 comments

Comments

@iamdriz
Copy link

iamdriz commented Jan 9, 2015

How can I communicate between two BrowserWindows in atom-shell?

I have been using Intercom.js https://github.com/diy/intercom.js/ for a project which works fine in the browser world, but doesn't work in the atom-shell world... Any ideas for how to get Intercom.js working? Or an alternative?

@iamdriz
Copy link
Author

iamdriz commented Jan 9, 2015

I need to be able to do complex communications like this in Window 1:

intercom.emit('notice', { func: 'buildGame', params: [boxes, winner] });

And in Window 2:

intercom.on('notice', function(data) {
    if(data.func){
        var callback = data.func;
        if(data.params) {
            var params = [];
            for(var i=0;i<data.params.length;i++)
            {
                params.push(data.params[i]);
            }
            window[callback].apply(window, params);
        } else {
            window[callback]();
        }
    }
});

So this might call buildGame(6, 4); in Window 2

I've seen this: https://github.com/atom/atom-shell/blob/master/docs/api/ipc-browser.md

But how would I do the same thing using IPC? As both of those chunks of code live inside the individual browser html pages and not in server-side JS.

@bwin
Copy link
Contributor

bwin commented Jan 9, 2015

In your browser-code (what you call "server-side") you hold references to your BrowserWindows.
From the renderer-code ("frontend"; inside BrowserWindow) you send msgs through IPC to the browser-code, which can send it to the BrowserWindow.
Edit: So there's one level of indirection involved.
BrowserWindow1 -> BrowserCode -> BrowserWindow2
Maybe this has gotten more comfortable in the meantime, then somebody will tell us.

@iamdriz
Copy link
Author

iamdriz commented Jan 9, 2015

Okay so from my understanding, this is how I would do it:

index1.html

ipc.send('asynchronous-message', { func: 'buildGame', params: [boxes, winner] });

index2.html

ipc.on('asynchronous-message', function(event, data) {
  if(data.func){
        var callback = data.func;
        if(data.params) {
            var params = [];
            for(var i=0;i<data.params.length;i++)
            {
                params.push(data.params[i]);
            }
            window[callback].apply(window, params);
        } else {
            window[callback]();
        }
    }
});

But the code is inside the BrowserWindow HTML pages... and I haven't got anything in the server-side bit (e.g. the main.js) regarding the ipc...

Is that correct? If not, what additional code do I need at the server-side to handle this?

@bwin
Copy link
Contributor

bwin commented Jan 9, 2015

No, you send your asynchronous-message from index1.html to your main.js. There you need to receive it and send it to index2.html.
Sorry, haven't got time to write example code.
Edit IPC works only between Browser and Renderer (or the other way, but not between 2 Renderers).
(But things move fast around here, so correct me if I'm wrong.)

@bwin
Copy link
Contributor

bwin commented Jan 9, 2015

Sorry, forgot to mention that you send from Browser to Renderer with yourBrowserWindow.webContents.send(channel, args...).
see https://github.com/atom/atom-shell/blob/master/docs/api/browser-window.md#webcontentssendchannel-args

@iamdriz
Copy link
Author

iamdriz commented Jan 9, 2015

So I need a combination of both to do what I want?

If possible, it'd be awesome to see an example of what needs to go in index1.html, index2.html and main.js to do what I posted above, as I'm confused.

@bwin
Copy link
Contributor

bwin commented Jan 9, 2015

yes.

Very simple example:

main.js

win1 = new BrowserWindow ... // index1.html
win2 = new BrowserWindow ... // index2.html
ipc.on('my-msg', function(event, arg) {
  win2.webContents.send('my-msg', arg); // sorry, had a typo here. fixed it
  // if you need communication in both ways, you have to check event.sender
  // then you know where it's coming from and therefore know where to send it
  // EDIT: or you could use channels like 'sendToWin1' and 'sendToWin2'
});

index1.html

ipc.send('my-msg', 'hi');

index2.html

ipc.on('my-msg', function(arg) {
  console.log('this was sent from win1', arg);
});

@bwin
Copy link
Contributor

bwin commented Jan 9, 2015

Don't use remote for ipc. There are actually 2 different ipc modules in atom-shell. require('ipc') uses the right one in respect to where you're calling it from.
Have a look at
https://github.com/atom/atom-shell/blob/master/docs/api/ipc-browser.md
and
https://github.com/atom/atom-shell/blob/master/docs/api/ipc-renderer.md

@bwin
Copy link
Contributor

bwin commented Jan 9, 2015

I created a Gist for you at https://gist.github.com/bwin/5ed15cc0620a6a63f081
In the devtools-console of win1 call sendIpcMsg() and you send a simple msg to win2.
Edit: this should be enough to get you started.

@iamdriz
Copy link
Author

iamdriz commented Jan 9, 2015

@bwin I've got it working :) Your typo threw me but it's all working now. Thanks.

@iamdriz iamdriz closed this as completed Jan 9, 2015
@bwin
Copy link
Contributor

bwin commented Jan 9, 2015

👍

@Altiano
Copy link

Altiano commented Apr 18, 2016

Why there is no direct communication ? It could be more simple to write, right?

@iamdriz
Copy link
Author

iamdriz commented Apr 18, 2016

@Altiano There is. You just need to make sure that it comes from where the process was spawned.

@Altiano
Copy link

Altiano commented Apr 19, 2016

I mean from a renderer process to another one.. How.?

@anaisbetts
Copy link
Contributor

let myWindows = require('remote').getAllWindows();
myWindows[1].webContents.send('an-event-from-window-zero');

@Altiano
Copy link

Altiano commented Apr 19, 2016

this probably work, but how can you be sure that myWindows[1] would return the first window ?

@Altiano
Copy link

Altiano commented Apr 19, 2016

After some test, this is what I do:

let myWindow = require('remote').BrowserWindow.fromId(id);
myWindow.webContents.send('an-event-from-window-zero');

@greggman
Copy link
Contributor

greggman commented Oct 21, 2016

let myWindow = require('remote').BrowserWindow.fromId(id);
myWindow.webContents.send('an-event-from-window-zero');

That works but replying to the sender does not. In other words

ipcRenderer.on('back-at-cha', (event) => {
  console.log("here!");
});

let myWindows = require('remote').getAllWindows();
myWindows[1].webContents.send('an-event-from-window-zero');

In window 1

ipcRenderer.on('an-event-from-window-zero', (event) => {
  event.sender.send('back-at-cha');   // doesn't seem to arrive back at window that send the msg
});

I've implemented a probaby crappy solution here but that was before I found this thread so I'm wondering if there is a simpler solution

@greggman
Copy link
Contributor

greggman commented Nov 6, 2016

Just FYI, I pushed a major change to other-window-ipc. The new one uses channels which makes certain uses much easier. A channel listens for connections. Each channel can have multiple streams.

@dtaburetkin
Copy link

dtaburetkin commented Nov 21, 2017

What wrong with:

main
const EventEmitter = require('events')
class MyEmitter extends EventEmitter {}
global.events = new MyEmitter()

any js file in project
var events = require('electron').remote.getGlobal('events')
events.on('event', () => {
console.log('an event occurred!')
})
events.emit('event')

does not work?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants