Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Note: Starting in Gecko 17.0, nsIBaseWindow.nativeHandle provides the handle (HWND [Widows], GdkWindow* [Linux], NSWindow* [MacOSX],...) of a top-level window, for all plateforms, as a string.

When working on Windows platforms, many APIs and frameworks require a window handle (HWND type). Since Mozilla tries to be as cross-platform as possible, it can be difficult to get the handle you need.

Note: Starting in Gecko 2.0, only the top level browser window has an HWND. Web content windows (in tabs) do not have their own HWNDs. Typically the top level browser window HWND has no children, although if there are windowed plugins (such as Flash) visible in the window, they will have HWNDs whose parent is the top level browser window HWND.

Here is some simple code that can get access to Mozilla window handles. This code can be used from external application or from an XPCOM component within an extension.

Finding the content window handle

 HWND hContent = 0;

 // first we need to find the main browser window
 HWND hFF = ::FindWindowEx(0, 0, "MozillaUIWindowClass", 0);
 if (hFF) {
    // next we step down through a fixed structure
    HWND hTemp;
    hTemp = ::FindWindowEx(hFF, 0, "MozillaWindowClass", 0);
    hTemp = ::FindWindowEx(hTemp, 0, "MozillaWindowClass", 0);

    // assume only 1 window at this level has children
    // and the 1 with children is the one we want
    HWND hChild = ::GetWindow(hTemp, GW_CHILD);
    while (hTemp && !hChild) {
      hTemp = ::GetWindow(hTemp, GW_HWNDNEXT);
      hChild = ::GetWindow(hTemp, GW_CHILD);
    }

    // did we find a window with children?
    // that child is hopefully the content window
    if (hTemp) {
      hTemp = ::GetWindow(hTemp, GW_CHILD);
      hContent = ::FindWindowEx(hTemp, 0, "MozillaContentWindowClass", 0);
    }
 }

 // at this point hContent is NULL or the content window HWND

I am not sure how "fragile" the assumptions are about the window structure, but it matched the values I got from SPY++.

Another technique is to use the Accessibility framework, see for example https://developer.mozilla.org/en/docs..._of_Interfaces

Another way to find a window handle...

Is to query it from an object. Once you have a docShell, QueryInterface it into nsIBaseWindow, call GetMainWidget on result, and then call GetNativeData(NS_NATIVE_WINDOW).

Like this

HWND GetHWND(nsIBaseWindow *window) 

{
  nsCOMPtr< nsIWidget > widget;
  window->GetMainWidget(getter_AddRefs(widget));

  if (widget)
    return (HWND) widget->GetNativeData(NS_NATIVE_WINDOW);
}

 Yet Another way to find a window handle (parent window handle)

This method is for people who want to get the top level window HWND from the window object in javascript. Comparing to the method above, by using this method, you don't have to compile your component with nsIWidget.h and other bunchs of h files that should not be exposed to outside, and could change every time Firefox updates, all you need is nsIBaseWindow.idl(It's not in gecko_sdk, get this from the latest Firefox source, or https://mxr.mozilla.org/mozilla/sourc...BaseWindow.idl), and use xpidl to compile it to .h file, although that's stll a unfrozen interface, but it should be a lot better. Notice that by using only the C++ part of this code will get the the parent window handle of the nsIBaseWindow you give as a param.  That means if you use the top level nsIBaseWindow as a param, NULL will be returned in the chain and cause crash of Firefox, that's a bug of firefox.(https://bugzilla.mozilla.org/show_bug.cgi?id=489045)

Now, let's move forward. First, in JavaScript, the code gets the nsIBaseWindow we want, it's a direct child of the top nsIBaseWindow.

        var baseWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                        .getInterface(Components.interfaces.nsIWebNavigation)
                        .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
                        .treeOwner
                        .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                        .getInterface(Components.interfaces.nsIBaseWindow);

Then in C++ part, a function take nsIBaseWindow as param

HWND getParentWindowHWND(nsIBaseWindow *window) 

{
	nativeWindow hwnd;
	nsresult rv = window->GetParentNativeWindow(&hwnd);
	if (NS_FAILED(rv)) return NULL;
	return (HWND)hwnd;
}

That's it; use with caution!

OS Specific Examples Using Javascript (js-ctypes) nsIBaseWindow -> nativeHandle

In all of the examples below, the native handle to the most recent navigator:browser is obtained and then it is focused. Run the snippets below from the Scratchpad in Environment > Browser.

Recall that nsIBaseWindow -> nativeHandle returns the following in the different operating systems:

  • Windows - HWND
  • Mac OS X - NSWindow*
  • Linux - GdkWindow* (it will be GdkWindow* no matter what desktop/window manager) is in use, for explanation why see the article: Standard OS Libraries - UNIX Section)

Windows

Components.utils.import('resource://gre/modules/Services.jsm');
var browserWindow = Services.wm.getMostRecentWindow('navigator:browser');
if (!browserWindow) {
    throw new Error('No browser window found');
}

var baseWindow = browserWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIWebNavigation)
                              .QueryInterface(Ci.nsIDocShellTreeItem)
                              .treeOwner
                              .QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIBaseWindow);

var hwndString = baseWindow.nativeHandle;

Components.utils.import('resource://gre/modules/ctypes.jsm');

var user32 = ctypes.open('user32.dll');

/* https://msdn.microsoft.com/en-us/library/ms633539%28v=vs.85%29.aspx
 * BOOL WINAPI SetForegroundWindow(
 *   __in_ HWND hWnd
 * );
 */
var SetForegroundWindow = user32.declare('SetForegroundWindow', ctypes.winapi_abi,
    ctypes.bool, // return BOOL
    ctypes.voidptr_t // HWND
);

var hwnd = ctypes.voidptr_t(ctypes.UInt64(hwndString));
var rez_SetForegroundWindow = SetForegroundWindow(hwnd);

console.log('rez_SetForegroundWindow:', rez_SetForegroundWindow, rez_SetForegroundWindow.toString());

user32.close();

Mac OS X

Objective-C

Components.utils.import('resource://gre/modules/Services.jsm');
var browserWindow = Services.wm.getMostRecentWindow('navigator:browser');
if (!browserWindow) {
    throw new Error('No browser window found');
}

var baseWindow = browserWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIWebNavigation)
                              .QueryInterface(Ci.nsIDocShellTreeItem)
                              .treeOwner
                              .QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIBaseWindow);

var NSWindowString = baseWindow.nativeHandle;

Components.utils.import('resource://gre/modules/ctypes.jsm');

var objc = ctypes.open(ctypes.libraryName('objc'));

// types
let id = ctypes.voidptr_t;
let SEL = ctypes.voidptr_t;

// constants
let nil = ctypes.voidptr_t(0);

//common functions
let sel_registerName = objc.declare('sel_registerName', ctypes.default_abi, SEL, ctypes.char.ptr);
let objc_msgSend = objc.declare('objc_msgSend', ctypes.default_abi, id, id, SEL, '...');

/* https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSApplication_Class/index.html#//apple_ref/occ/instp/NSApplication/orderFront:
 *   [NSWindowPtr orderFront:nil]
 */
var orderFront = sel_registerName('orderFront:');

var NSWindowPtr = ctypes.voidptr_t(ctypes.UInt64(NSWindowString));
var rez_orderFront = objc_msgSend(NSWindowPtr, orderFront, nil);

console.log('rez_orderFront:', rez_orderFront, rez_orderFront.toString());

objc.close();

Unix

Under Unix systems, the nativeHandle holds a string address to a GdkWindow* (the asterik/star means pointer). The string is made into an actual GdkWindow* like this:

var GdkWindow = ctypes.StructType('GdkWindow');
var GDKWindowPtrString = baseWindow.nativeHandle;
var GdkWinPtr = GdkWindow.ptr(ctypes.UInt64(GDKWindowPtrString));

Working with GdkWindow*

GdkWindow* to XID
var GdkWindow = ctypes.StructType('GdkWindow');
var GdkDrawable = ctypes.StructType('GdkDrawable');
var CARD32 = /^(Alpha|hppa|ia64|ppc64|s390|x86_64)-/.test(Services.appinfo.XPCOMABI) ? ctypes.unsigned_int : ctypes.unsigned_long;
var XID =  CARD32;

var gdk = ctypes.open('libgdk-x11-2.0.so.0');
var gdk_x11_drawable_get_xid = gdk.declare('gdk_x11_drawable_get_xid', ctypes.default_abi, XID, GdkDrawable.ptr);

var GDKWindowPtrString = baseWindow.nativeHandle;
var GdkWinPtr = GdkWindow.ptr(ctypes.UInt64(GDKWindowPtrString));
var GdkDrawPtr = ctypes.cast(GdkWinPtr, GdkDrawable.ptr);

var xidOfWin = gdk_x11_drawable_get_xid(GdkDrawPtr);
GdkWindow* to GtkWindow*

How to get the GtkWindow* from the GdkWindow*? Mozilla developers have put the reference to the GtkWindow* into the GdkWindow* "user data", as a back reference. The "user data" is accessed by using the GDK function of gdk_window_get_user_data.

var GdkWindow = ctypes.StructType('GdkWindow');
var gpointer = ctypes.voidptr_t;
var GtkWindow = ctypes.StructType('GtkWindow');

var GDKWindowPtrString = baseWindow.nativeHandle;
var GdkWinPtr = GdkWindow.ptr(ctypes.UInt64(GDKWindowPtrString));

var gptr = gpointer();
gdk_window_get_user_data(GdkWinPtr, gptr.address());

var GtkWinPtr = ctypes.cast(gptr, GtkWindow.ptr);

Working with GtkWindow*

GtkWindow* to XID
// soon to come
GtkWindow* to GdkWindow*

How to get a GdkWindow* from the GtkWindow*? There is a GTK+ provided function for this, gtk_widget_get_window. The GtkWindow* is cast to a GtkWidget*, and this is passed to the gtk_widget_get_window function which returns a GdkWindow*.

var GdkWindow = ctypes.StructType('GdkWindow');
var gpointer = ctypes.voidptr_t;
var GtkWindow = ctypes.StructType('GtkWindow');
var GtkWidget = ctypes.StructType('GtkWidget');

/***** this part is from the GdkWindow* to GtkWindow* example above
var GDKWindowPtrString = baseWindow.nativeHandle;
var GdkWinPtr = GdkWindow.ptr(ctypes.UInt64(GDKWindowPtrString));
 
var gdk = ctypes.open('libgdk-x11-2.0.so.0');
var gdk_window_get_user_data = gdk.declare('gdk_window_get_user_data', ctypes.default_abi, ctypes.void_t, GdkWindow.ptr, gpointer.ptr);
var gptr = gpointer();
gdk_window_get_user_data(GdkWinPtr, gptr.address());
 
var GtkWinPtr = ctypes.cast(gptr, GtkWindow.ptr); // we now have GtkWindow*
 */

// lets take it back to GdkWindow*
var gtk = ctypes.open('libgtk-x11-2.0.so.0');
var gtk_widget_get_window = gtk.declare('gtk_widget_get_window', ctypes.default_abi, GdkWindow.ptr, GtkWidget.ptr); // for getGdkWindowFromGtkWindow
 
var gtkWidgetPtr = ctypes.cast(GtkWinPtr, GtkWidget.ptr);
var backTo_gdkWinPtr = gtk_widget_get_window(gtkWidgetPtr);
 

Working with XID

 
XID to GdkWindow*
// soon to come
XID to GtkWindow*
// soon to come

Now onto the examples!

Examples

GDK
Components.utils.import('resource://gre/modules/Services.jsm');
var browserWindow = Services.wm.getMostRecentWindow('navigator:browser');
if (!browserWindow) {
    throw new Error('No browser window found');
}

var baseWindow = browserWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIWebNavigation)
                              .QueryInterface(Ci.nsIDocShellTreeItem)
                              .treeOwner
                              .QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIBaseWindow);

var GDKWindowPtrString = baseWindow.nativeHandle;

Components.utils.import('resource://gre/modules/ctypes.jsm');

var gdk = ctypes.open('libgdk-x11-2.0.so.0');

// types
let guint32 = ctypes.uint32_t;
let GdkWindow = ctypes.StructType('GdkWindow');

// https://developer.gnome.org/gdk3/stable/gdk3-Windows.html#gdk-window-focus
var gdk_window_focus = gdk.declare('gdk_window_focus', ctypes.default_abi, ctypes.void_t, GdkWindow.ptr, guint32);

// https://developer.gnome.org/gdk2/stable/gdk2-X-Window-System-Interaction.html#gdk-x11-get-server-time
var gdk_x11_get_server_time = gdk.declare('gdk_x11_get_server_time', ctypes.default_abi, guint32, GdkWindow.ptr);

var browserWindow_madeIntoGdkWinPtr = GdkWindow.ptr(ctypes.UInt64(GDKWindowPtrString));

var rez_gst = gdk_x11_get_server_time(browserWindow_madeIntoGdkWinPtr);
console.info('rez_gst:', rez_gst, uneval(rez_gst)); // return is a number of ms since the computer (XServer) was on

var rez_gwf = gdk_window_focus(browserWindow_madeIntoGdkWinPtr, rez_gst);
console.info('rez_gwf:', rez_gwf, uneval(rez_gwf)); // return is void so this will be undefined

gdk.close();
GTK+
Components.utils.import('resource://gre/modules/Services.jsm');
var browserWindow = Services.wm.getMostRecentWindow('navigator:browser');
if (!browserWindow) {
    throw new Error('No browser window found');
}

var baseWindow = browserWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIWebNavigation)
                              .QueryInterface(Ci.nsIDocShellTreeItem)
                              .treeOwner
                              .QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIBaseWindow);

var GDKWindowPtrString = baseWindow.nativeHandle;

Components.utils.import('resource://gre/modules/ctypes.jsm');

var gdk = ctypes.open('libgdk-x11-2.0.so.0');
var gtk = ctypes.open('libgtk-x11-2.0.so.0');

// types
let guint32 = ctypes.uint32_t;
let GdkWindow = ctypes.StructType('GdkWindow');
let gpointer = ctypes.voidptr_t;
let GtkWindow = ctypes.StructType('GtkWindow');

//https://developer.gnome.org/gdk3/stable/gdk3-Windows.html#gdk-window-get-user-data
var gdk_window_get_user_data = gdk.declare('gdk_window_get_user_data', ctypes.default_abi, ctypes.void_t, GdkWindow.ptr, gpointer.ptr);

//https://developer.gnome.org/gtk3/stable/GtkWindow.html#gtk-window-present
var gtk_window_present = gtk.declare('gtk_window_present', ctypes.default_abi, ctypes.void_t, GtkWindow.ptr);

//https://developer.gnome.org/gtk3/stable/GtkWindow.html#gtk-window-present-with-time
var gtk_window_present_with_time = gtk.declare('gtk_window_present_with_time', ctypes.default_abi, ctypes.void_t, GtkWindow.ptr, guint32);

// gdk_x11_get_server_time is needed for gtk_window_present_with_time
// https://developer.gnome.org/gdk2/stable/gdk2-X-Window-System-Interaction.html#gdk-x11-get-server-time
var gdk_x11_get_server_time = gdk.declare('gdk_x11_get_server_time', ctypes.default_abi, guint32, GdkWindow.ptr);

var browserWindow_madeIntoGdkWinPtr = GdkWindow.ptr(ctypes.UInt64(GDKWindowPtrString));

var gptr = gpointer();
var rez_gwgud = gdk_window_get_user_data(browserWindow_madeIntoGdkWinPtr, gptr.address());
console.info('rez_gwgud:', rez_gwgud, /*rez_gwgud.toString(),*/ uneval(rez_gwgud)); // return is void so cant do .toString on it

var browserWindow_madeIntoGtkWindowPtr = ctypes.cast(gptr, GtkWindow.ptr);

// focusing window this way is better, so it maintains proper history in case you or some other app want to focus "most recent window" by timestamp
// var rez_gst = gdk_x11_get_server_time(browserWindow_madeIntoGdkWinPtr);
// console.info('rez_gst:', rez_gst, uneval(rez_gst)); // return is a number of ms since the computer (XServer) was on
// var rez_gwpwt = gtk_window_present_with_time(browserWindow_madeIntoGtkWindowPtr, rez_gst);
// console.info('rez_gwaf:', rez_gwpwt, uneval(rez_gwpwt));

var rez_gwp = gtk_window_present(browserWindow_madeIntoGtkWindowPtr);
console.info('rez_gwaf:', rez_gwaf, uneval(rez_gwaf));

gdk.close();
gtk.close();
X11

WARNING This example below does not focus a window yet, it does convert from a GdkWindow* to a XID and that's it, the code for focusing the window is soon to come.

Components.utils.import('resource://gre/modules/Services.jsm');
var browserWindow = Services.wm.getMostRecentWindow('navigator:browser');
if (!browserWindow) {
    throw new Error('No browser window found');
}

var baseWindow = browserWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIWebNavigation)
                              .QueryInterface(Ci.nsIDocShellTreeItem)
                              .treeOwner
                              .QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIBaseWindow);

var GDKWindowPtrString = baseWindow.nativeHandle;

Components.utils.import('resource://gre/modules/ctypes.jsm');

var gdk = ctypes.open('libgdk-x11-2.0.so.0');
var x11 = ctypes.open('libX11.so.6');

// types
let guint32 = ctypes.uint32_t;
let GdkWindow = ctypes.StructType('GdkWindow');
let GdkDrawable = ctypes.StructType('GdkDrawable');
let CARD32;
if (/^(Alpha|hppa|ia64|ppc64|s390|x86_64)-/.test(Services.appinfo.XPCOMABI)) {
    CARD32 = ctypes.unsigned_int;
} else {
    CARD32 = ctypes.unsigned_long;
}
let XID =  CARD32;

//https://developer.gnome.org/gdk2/stable/gdk2-X-Window-System-Interaction.html#gdk-x11-drawable-get-xid
var gdk_x11_drawable_get_xid = gdk.declare('gdk_x11_drawable_get_xid', ctypes.default_abi, XID, GdkDrawable.ptr);


var browserWindow_madeIntoGdkWinPtr = GdkWindow.ptr(ctypes.UInt64(GDKWindowPtrString));
var browserWindow_madeIntoGdkDrawable = ctypes.cast(browserWindow_madeIntoGdkWinPtr, GdkDrawable.ptr);

var browserWindow_madeIntoXID = gdk_x11_drawable_get_xid(browserWindow_madeIntoGdkDrawable);
console.info('browserWindow_madeIntoXID:', browserWindow_madeIntoXID, browserWindow_madeIntoXID.toString(), uneval(browserWindow_madeIntoXID));

// the code to focus the window is soon to come, its long and messy it needs to be made into a simple readable good for example. to see the messy code see here: https://gist.github.com/Noitidart/60aab0a96f060240614f#file-_ff-addon-snippet-x11_focusmostrecentwindowofpid-js-L354

gdk.close();
x11.close();

See Also

Document Tags and Contributors

 Last updated by: Noitidart,