2

I want to use different XPCOM interfaces in Firefox Extension, here is an example taken from their API:

var domWindowUtils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                     .getInterface(Components.interfaces.nsIDOMWindowUtils);

But I can't use it in my background script because object Window is undefined:

window.QueryInterface is not a function

Please guide me in right direction.

P.S. What is actually available in a global scope for background scripts? I can't seem to find a single clue in documentation.

alandarev
  • 8,349
  • 2
  • 34
  • 43

2 Answers2

5

The issue is that Firefox extensions do not run in the context of any particular window. As such, they often do not have the window object defined, or it is defined as something which you are not expecting if you are not familiar with writing extension code. This is particularly true if you are approaching this from the point of view of writing JavaScript for use within an HTML page. Extensions operate in a significantly larger context which includes the entire browser and all windows and tabs. Thus, there is no automatically appropriate window to use as the window object. In the context of an extension, each HTML page is just a part of the whole.

You can obtain each primary browser window through the use of nsIWindowMediator. The following function, from MDN, will run the function you pass to it once for each open window:

Components.utils.import("resource://gre/modules/Services.jsm");
function forEachOpenWindow(todo)  // Apply a function to all open browser windows
{
    var windows = Services.wm.getEnumerator("navigator:browser");
    while (windows.hasMoreElements())
      todo(windows.getNext().QueryInterface(Components.interfaces.nsIDOMWindow));
}

You will often want to find the window for the most recent browser/tab which was accessed by the user. The following code will define and set the window variable to the most recently used browser/tab. It will work either in the Add-on SDK, or in overlay/bootstrap extensions depending on which portion you un-comment.

For more information about using windows in a Firefox extension, you should see Working with windows in chrome code and perhaps Tabbed browser.

if (window === null || typeof window !== "object") {
    //If you do not already have a window reference, you need to obtain one:
    //  Add a "/" to un-comment the code appropriate for your add-on type.
    /* Add-on SDK:
    var window = require('sdk/window/utils').getMostRecentBrowserWindow();
    //*/
    /* Overlay and bootstrap (from almost any context/scope):
    var window=Components.classes["@mozilla.org/appshell/window-mediator;1"]
                         .getService(Components.interfaces.nsIWindowMediator)
                         .getMostRecentWindow("navigator:browser");        
    //*/
}

Alternately using Services.jsm to access nsIWindowMediator:

/* Overlay and bootstrap:
Components.utils.import("resource://gre/modules/Services.jsm");
//*/
if (window === null || typeof window !== "object") {
    //If you do not already have a window reference, you need to obtain one:
    //  Add a "/" to un-comment the code appropriate for your add-on type.
    /* Add-on SDK:
    var window = require('sdk/window/utils').getMostRecentBrowserWindow();
    //*/
    /* Overlay and bootstrap (from almost any context/scope):
    var window = Services.wm.getMostRecentWindow("navigator:browser");
    //*/
}

Here are some additional variables which might be useful to have available, depending on what you are doing:

if (typeof document === "undefined") {
    //If there is no document defined, get it
    var document = window.content.document;
}

if (typeof gBrowser === "undefined") {
    //If there is no gBrowser defined, get it
    var gBrowser = window.gBrowser;
}

var tab = gBrowser.selectedTab;
var browserForTab = gBrowser.getBrowserForTab( tab );
var notificationBox = gBrowser.getNotificationBox( browserForTab );
var ownerDocument = gBrowser.ownerDocument;

NOTE: The content of this answer was primarily taken from my answers here and here, but is based on code from MDN. For me, the code to traverse all open browser windows has its origin in the original article the MDN article How to convert an overlay extension to restartless is based on.

Community
  • 1
  • 1
Makyen
  • 31,849
  • 12
  • 86
  • 121
3

A quick and dirty way for testing, and sometimes real application is Services.wm.getMostRecentWindow('navigator:browser'), or you can use null or any other windowType.

Noitidart
  • 35,443
  • 37
  • 154
  • 323