Last Comment Bug 760802 - JavaScript easy access to native window handle
: JavaScript easy access to native window handle
Status: RESOLVED FIXED
:
Product: Core
Classification: Components
Component: Widget (show other bugs)
: 12 Branch
: x86 Linux
: -- normal (vote)
: mozilla17
Assigned To: foudfou
:
Mentors:
Depends on: 777243
Blocks: 791975
  Show dependency treegraph
 
Reported: 2012-06-02 06:27 PDT by foudfou
Modified: 2012-09-18 03:29 PDT (History)
4 users (show)
ryanvm: in‑testsuite+
See Also:
Crash Signature:
(edit)
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---


Attachments
basic implementation (7.88 KB, patch)
2012-06-13 14:09 PDT, foudfou
no flags Details | Diff | Review
basic implementation as String instead of Number (7.72 KB, patch)
2012-06-21 11:55 PDT, foudfou
no flags Details | Diff | Review
Adds JS nativeHandler attribute for nsIBaseWindow (10.47 KB, patch)
2012-06-29 06:31 PDT, foudfou
no flags Details | Diff | Review
attribute as DOMString (10.81 KB, patch)
2012-06-30 15:17 PDT, foudfou
no flags Details | Diff | Review
revised with nsPrintfCString (11.03 KB, patch)
2012-07-01 14:06 PDT, foudfou
roc: review+
Details | Diff | Review
with spacing fixes (10.78 KB, patch)
2012-07-21 01:50 PDT, foudfou
no flags Details | Diff | Review

Description foudfou 2012-06-02 06:27:32 PDT
User Agent: Mozilla/5.0 (X11; Linux i686; rv:12.0) Gecko/20100101 Firefox/12.0
Build ID: 20120424151726

Steps to reproduce:

It would be very convenient, for applications or addons interacting with the desktop or window manager, if nsIBaseWindow could expose its handle to the native window, in the form of an attribute in JS. This handle  could be passed on to js-ctypes for instance.

It should be an number representing a pointer to the native window (like a *GdkWindow or a HWND). I guess it should be whatever nsWindow::GetNativeData(NS_NATIVE_WINDOW) returns but in JS;

This news thread shows a practical use case: https://groups.google.com/d/msg/mozilla.dev.extensions/JXgOCHSK0ZU/bR5A2ZCZV3sJ
Comment 1 foudfou 2012-06-02 06:32:24 PDT
I'd be happy to work on this one.
Comment 2 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2012-06-07 12:12:50 PDT
The basic idea sounds reasonable to me. You'll have to cope with the possibilty of this method returning null. That will certainly be true for all non-root windows.
Comment 3 foudfou 2012-06-13 14:09:50 PDT
Created attachment 632872 [details] [diff] [review]
basic implementation

See attachment for a basic/proof-of-concept implementation: nativeHandle returns the actual address of the native window as a jsval (not a pointer as one could expecte).

However, I begin to have doubts about the usefulness of such a property:

1. getting a handle is relatively easy with ctypes. Extensions do that well already: see http://forums.mozillazine.org/viewtopic.php?f=19&t=2449775 (windows) or https://addons.mozilla.org/en/firefox/addon/firetray/ (linux).

2. I can't seem to be able to make use of the memory address provided by nativeHandle: I can build a ctypes object out of it (gdk.GdkWindow.ptr), but it does not behave properly when I try to manipulate it, for example when fetching the GtkWindow stored in the user_data of the GdkWindow.

Here is how I re-construct the ctypes window object:

  let baseWin = win.QueryInterface(Ci.nsIInterfaceRequestor)
    .getInterface(Ci.nsIWebNavigation)
    .QueryInterface(Ci.nsIDocShellTreeItem)
    .treeOwner
    .QueryInterface(Ci.nsIInterfaceRequestor)
    .nsIBaseWindow;
  let nativeHandle = baseWin.nativeHandle;
  let gdkwPtr = ctypes.uintptr_t(nativeHandle).address();
  let gdkWindow = ctypes.cast(gdkwPtr, gdk.GdkWindow.ptr);
Comment 4 foudfou 2012-06-21 11:55:24 PDT
Created attachment 635402 [details] [diff] [review]
basic implementation as String instead of Number

chatting with Yoric, it turned out JS Numbers can only store 32 bits numbers (hence ctypes.UInt64!). So here is another basic implementation which returns a String that can easily be parsed by ctypes, like this:

      let nativeHandle = baseWin.nativeHandle;
      let gdkw = new gdk.GdkWindow.ptr(ctypes.UInt64(nativeHandle));

Note this version returns the protected pointer to the actual native window (HWND, GdkWindow*, ...), instead of the actual address of the window as previously implemented.
Comment 5 foudfou 2012-06-21 12:42:53 PDT
The problems mentioned in comment 3 point 2. are gone, and it's relatively easy to get the toplevel GtkWindow, with a gdk_window_get_user_data() followed by a gtk_widget_get_toplevel().
Comment 6 foudfou 2012-06-29 06:31:04 PDT
Created attachment 637885 [details] [diff] [review]
Adds JS nativeHandler attribute for nsIBaseWindow

tested on Try: https://tbpl.mozilla.org/?tree=Try&rev=7f3510e83597 (I hope I didn't miss anything)

Few things to note:
* nativeHandle only implemented for nsXULWindow, not for embedding nsWebBrowser, not for nsDocShell (is this needed ?)
* if nsXULWindow->mWindow is unlikely to be void, shouldn't nativeHandle throw NS_ERROR_UNEXPECTED instead returning of JSVAL_NULL ? If not, how to test a nsXULWindow without a mWindow ?
* jsapi.h included in nsIBAseWindow.idl for jsval. It this the proper way ?
Thank you
Comment 7 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2012-06-29 19:22:08 PDT
Comment on attachment 637885 [details] [diff] [review]
Adds JS nativeHandler attribute for nsIBaseWindow

Review of attachment 637885 [details] [diff] [review]:
-----------------------------------------------------------------

::: widget/nsIBaseWindow.idl
@@ +163,5 @@
> +
> +  @throws NS_ERROR_NOT_IMPLEMENTED for non-toplevel widgets, or
> +  NS_ERROR_UNEXPECTED if conversion fails
> +  */
> +  [implicit_jscontext] readonly attribute jsval nativeHandle;

Why not declare it as a DOMString instead of a jsval?
Comment 8 foudfou 2012-06-30 15:17:29 PDT
Created attachment 638153 [details] [diff] [review]
attribute as DOMString

There is no reason to declare the attribute as a jsval, as long as the string is available to JS. I guess DOMString is even better.
Comment 9 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2012-07-01 03:30:49 PDT
Comment on attachment 638153 [details] [diff] [review]
attribute as DOMString

Review of attachment 638153 [details] [diff] [review]:
-----------------------------------------------------------------

::: widget/nsIBaseWindow.idl
@@ +156,5 @@
> +	This is the handle (HWND, GdkWindow*, ...) to the native window of the
> +	control, exposed as a DOMString.
> +
> +  @return DOMString in hex format with "0x" prepended, or null if mainWidget
> +  undefined

It seems you don't actually return null, but an empty string if there is no native window.

It might be better to simply return an empty string for all failure conditions. I'm not sure it's worth trying to distinguish different failure conditions.

::: widget/tests/test_bug760802.html
@@ +57,5 @@
> +  "nativeHandle should not be implemented for nsDocShell"
> +);
> +
> +SimpleTest.ok(typeof(nativeHandle) === "string", "nativeHandle should be a string");
> +SimpleTest.ok(nativeHandle.match(/^0x[0-9a-f]+/), "nativeHandle should have a memory address format");

You don't need to prefix ok() and is() with SimpleTest, do you?

Have you tested this on Windows? Visual C++ produces capital hex digits for %p. Maybe you should put a tolower method call somewhere so only lower-case digits are returned by this API.

::: xpfe/appshell/src/nsXULWindow.cpp
@@ +753,5 @@
> +       |Number| for instance) */
> +    char* addrStr = PR_smprintf("0x%p", nativeWindowPtr);
> +    if (!addrStr)
> +      return NS_ERROR_UNEXPECTED;
> +    aNativeHandle = NS_ConvertASCIItoUTF16(addrStr);

You could use nsPrintfCString instead for slightly simpler code (and avoiding an error path).
Comment 10 foudfou 2012-07-01 14:06:09 PDT
Created attachment 638225 [details] [diff] [review]
revised with nsPrintfCString

> It might be better to simply return an empty string for all failure conditions.

Do you mean it should not even throw NS_NOT_IMPLEMENTED for non-XULWindows (i.e. nsDocShell and nsWebBrowser) and return an empty string instead ?

> You don't need to prefix ok() and is() with SimpleTest, do you?

Changed applied.

> Have you tested this on Windows? Visual C++ produces capital hex digits for %p.
> Maybe you should put a tolower method call somewhere so only lower-case digits
are returned by this API.

I haven't tested on Windows myself, but my last Try (https://tbpl.mozilla.org/?tree=Try&rev=ad3559d462f6) and this test

  ok(nativeHandle.match(/^0x[0-9a-f]+$/), "nativeHandle should have a memory address format");

tend to show that a tolower method call is not useful. nsPrintfCString uses PR_vsnprintf, which converts using lowercase digits.
Comment 11 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2012-07-01 15:57:25 PDT
> > It might be better to simply return an empty string for all failure conditions.
> 
> Do you mean it should not even throw NS_NOT_IMPLEMENTED for non-XULWindows
> (i.e. nsDocShell and nsWebBrowser) and return an empty string instead ?

Maybe. It doesn't really matter I guess. Leave it.

> tend to show that a tolower method call is not useful. nsPrintfCString uses
> PR_vsnprintf, which converts using lowercase digits.

OK!
Comment 12 foudfou 2012-07-20 04:57:34 PDT
Comment on attachment 638225 [details] [diff] [review]
revised with nsPrintfCString

roc, are you able to commit the patch as I don't have authorization yet ? Or should I add the checkin-needed keyword ? Is there anything I can do to help having the patch checked in ?
Comment 13 Patrick Cloke [:clokep] 2012-07-20 05:26:45 PDT
Drive by review comments:
- The spacing in embedding/browser/webBrowser/nsWebBrowser.cpp seems wrong (it seems to use 3 spaces, the added code uses 2).
- The comment in widget/nsIBaseWindow.idl has awful whitespace (some tabs, some two spaces).

Also, setting this to assigned...since it doesn't seem to be unconfirmed any longer.
Comment 14 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2012-07-20 09:44:58 PDT
Comment on attachment 638225 [details] [diff] [review]
revised with nsPrintfCString

Review of attachment 638225 [details] [diff] [review]:
-----------------------------------------------------------------

Please address those drive-by review comments, then reattach your patch with "checkin?" (no assignee) and someone will check it in :-)
Comment 15 foudfou 2012-07-21 01:50:40 PDT
Created attachment 644612 [details] [diff] [review]
with spacing fixes

Thank you Patrick for your careful review. I completely missed the spacing issue. It looks like some files have incorrect indentation and emacs/vim mode lines (see Bug 369322 for instance). I guess I'll need to file specific bug reports to correct some.

I also took the opportunity to remove this correction https://bugzilla.mozilla.org/attachment.cgi?id=638225&action=diff#a/testing/mochitest/static/xul.template.txt_sec1 which I believe belongs to a separate bug.

https://tbpl.mozilla.org/?tree=Try&rev=0cd412803918
Comment 16 foudfou 2012-07-21 05:04:38 PDT
Comment on attachment 644612 [details] [diff] [review]
with spacing fixes

Re-reading Roc's comment 14, I removed the review? flag and set checkin?.
Comment 17 Ryan VanderMeulen [:RyanVM] 2012-07-24 18:32:27 PDT
Comment on attachment 644612 [details] [diff] [review]
with spacing fixes

You can just use checkin-needed. Also, please follow the directions below for future patches. It makes life much easier for those checking in on your behalf. Thanks!
https://developer.mozilla.org/en/Creating_a_patch_that_can_be_checked_in
Comment 18 Ryan VanderMeulen [:RyanVM] 2012-07-24 19:07:00 PDT
https://hg.mozilla.org/integration/mozilla-inbound/rev/9dcd7470dc0b
Comment 19 Ed Morley [:emorley] 2012-07-25 08:10:34 PDT
https://hg.mozilla.org/mozilla-central/rev/9dcd7470dc0b
Comment 20 Robert O'Callahan (:roc) (Exited; email my personal email if necessary) 2012-09-17 13:31:11 PDT
Please make the test a chrome test

Note You need to log in before you can comment on or make changes to this bug.