mozilla
Your Search Results

    Finding window handles

    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 http://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 http://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');
    
    /* http://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,
    Hide Sidebar