The message manager

  • Revision slug: The_message_manager
  • Revision title: The message manager
  • Revision id: 57761
  • Created:
  • Creator: Sheppy
  • Is current revision? No
  • Comment 13 words removed

Revision Content

{{ gecko_minversion_header("2.0") }}

In order to support different parts of web content being handled in separate threads (such as out-of-process plugins), Gecko now features API that allows the browser to communicate with content processes by loading script files that add listeners to the content process's root event handling scope; those event listeners can then send messages back to the chrome process.

Note: Currently, this API only supports JavaScript.

The content process

For each tab, the child process has a JavaScript context and scope. This implements the {{ interface("nsIContentFrameMessageManager") }} and {{ interface("nsIDOMEventTarget") }} interfaces. This scope is above the current top level content window, so that capturing event listeners will be called first, using event listeners added in that scope. Event listeners added to the bubble phase will be called after listeners in the content page have had a chance to handle the event.

You can access the current top level window using the content attribute in the {{ interface("nsIContentFrameMessageManager") }}, and that interface's docShell attribute references the top level window's {{ interface("nsIDocShell") }} object.

The child process's scope also supports the methods from {{ interface("nsIDOMEventTarget") }}, as well as the methods added by {{ interface("nsIContentFrameMessageManager") }}.

Listening to messages coming from chrome

Calling {{ ifmethod("nsIDOMEventTarget", "addMessageListener") }} adds a listener to receive messages coming from chrome. Similarly, calling {{ ifmethod("nsIDOMEventTarget", "removeEventListener") }} removes listeners.

Sending messages to chrome

Call the {{ ifmethod("nsIContentFrameMessageManager", "sendSyncMessage") }} method to synchronously send a message to chrome.

The chrome process

On the chrome side, the chrome window and each {{ interface("nsIFrameLoader") }} object now have a messageManager attribute, which provides an {{ interface("nsIChromeFrameMessageManager") }} interface; these handle receiving messages from content processes by implementing sendSyncMessage() and loadFrameScript() to process messages and load script, respectively.

When a message is received from a content process, listeners in the {{ interface("nsIFrameLoader") }} object's message manager are called first, followed by the ones in the window's message manager.

Listening to messages coming from content

Calling {{ ifmethod("nsIDOMEventTarget", "addMessageListener") }} adds a listener to receive messages coming from content. Similarly, calling {{ ifmethod("nsIDOMEventTarget", "removeEventListener") }} removes listeners.

Sending messages to content

The {{ ifmethod("nsIChromeFrameMessageManager", "sendSyncMessage") }} method synchronously sends a message to content.

The {{ ifmethod("nsIChromeFrameMessageManager", "loadFrameScript") }} method tells the content process's root scope to load a script.

A simple example

This simple example forwards all clicks on HTML {{ HTMLElement("a") }} elements to chrome. This is a simplified example, and won't work for child elements, but it should help understand how the messaging system works.

The content process's code

This code runs in the content process to set up an event listener that forwards the click events to the chrome process.

addEventListener("click",
  function(e) {
    if (e.target instanceof Components.interfaces.nsIDOMHTMLAnchorElement &&
        sendSyncMessage("linkclick", { href : e.target.href })[0].cancel) {
      e.preventDefault();
    }
  },
  false);

This code runs in chrome to receive the click events.

messageManager.loadFrameScript("path://to/remote.js", true);
messageManager.addMessageListener("linkclick",
  function(m) {
    return { cancel: !confirm("Do you want to load " + m.json.href) };
  }
);

See also

Revision Source

<p>{{ gecko_minversion_header("2.0") }}</p>
<p>In order to support different parts of web content being handled in separate threads (such as <a href="/en/Plugins/Out_of_process_plugins" title="en/Plugins/Out of process plugins">out-of-process plugins</a>), Gecko now features API that allows the browser to communicate with content processes by loading script files that add listeners to the content process's root event handling scope; those event listeners can then send messages back to the chrome process.</p>
<div class="note"><strong>Note:</strong> Currently, this API only supports JavaScript.</div>
<h2>The content process</h2>
<p>For each tab, the child process has a JavaScript context and scope. This implements the {{ interface("nsIContentFrameMessageManager") }} and {{ interface("nsIDOMEventTarget") }} interfaces. This scope is above the current top level content window, so that capturing event listeners will be called first, using event listeners added in that scope. Event listeners added to the bubble phase will be called after listeners in the content page have had a chance to handle the event.</p>
<p>You can access the current top level window using the <code>content</code> attribute in the {{ interface("nsIContentFrameMessageManager") }}, and that interface's <code>docShell</code> attribute references the top level window's {{ interface("nsIDocShell") }} object.</p>
<p>The child process's scope also supports the methods from {{ interface("nsIDOMEventTarget") }}, as well as the methods added by {{ interface("nsIContentFrameMessageManager") }}.</p>
<h3>Listening to messages coming from chrome</h3>
<p>Calling {{ ifmethod("nsIDOMEventTarget", "addMessageListener") }} adds a listener to receive messages coming from chrome. Similarly, calling {{ ifmethod("nsIDOMEventTarget", "removeEventListener") }} removes listeners.</p>
<h3>Sending messages to chrome</h3>
<p>Call the {{ ifmethod("nsIContentFrameMessageManager", "sendSyncMessage") }} method to synchronously send a message to chrome.</p>
<h2>The chrome process</h2>
<p>On the chrome side, the chrome window and each {{ interface("nsIFrameLoader") }} object now have a <code>messageManager</code> attribute, which provides an {{ interface("nsIChromeFrameMessageManager") }} interface; these handle receiving messages from content processes by implementing <code>sendSyncMessage()</code> and <code>loadFrameScript()</code> to process messages and load script, respectively.</p>
<p>When a message is received from a content process, listeners in the {{ interface("nsIFrameLoader") }} object's message manager are called first, followed by the ones in the window's message manager.</p>
<h3>Listening to messages coming from content</h3>
<p>Calling {{ ifmethod("nsIDOMEventTarget", "addMessageListener") }} adds a listener to receive messages coming from content. Similarly, calling {{ ifmethod("nsIDOMEventTarget", "removeEventListener") }} removes listeners.</p>
<h3>Sending messages to content</h3>
<p>The {{ ifmethod("nsIChromeFrameMessageManager", "sendSyncMessage") }} method synchronously sends a message to content.</p>
<p>The {{ ifmethod("nsIChromeFrameMessageManager", "loadFrameScript") }} method tells the content process's root scope to load a script.</p>
<h2>A simple example</h2>
<p>This simple example forwards all clicks on HTML {{ HTMLElement("a") }} elements to chrome. This is a simplified example, and won't work for child elements, but it should help understand how the messaging system works.</p>
<h3>The content process's code</h3>
<p>This code runs in the content process to set up an event listener that forwards the click events to the chrome process.</p>
<pre class="brush: js">addEventListener("click",
  function(e) {
    if (e.target instanceof Components.interfaces.nsIDOMHTMLAnchorElement &amp;&amp;
        sendSyncMessage("linkclick", { href : e.target.href })[0].cancel) {
      e.preventDefault();
    }
  },
  false);
</pre>
<p>This code runs in chrome to receive the click events.</p>
<pre class="brush: js">messageManager.loadFrameScript("path://to/remote.js", true);
messageManager.addMessageListener("linkclick",
  function(m) {
    return { cancel: !confirm("Do you want to load " + m.json.href) };
  }
);
</pre>
<h2>See also</h2>
<ul> <li><a class=" link-https" href="https://wiki.mozilla.org/Content_Process_Event_Handlers" title="https://wiki.mozilla.org/Content_Process_Event_Handlers">Content Process Event Handlers</a> (design document)</li>
</ul>
Revert to this revision