Firefox 4.0b10でGreasemonkey 0.9.1のユーザスクリプトのwindowを共通にする改造(開発者orVimper向け)

2010/02/09追記: Firefox 4.0b11でもおk
2010/03/01追記: Firefox 4.0b12でもおk。のようだけど、時々うまく動かない事も
2010/03/14追記: Firefox 4.0 RC1でもおk

2012/01/04追記: Greasemonkey 0.9.13で動かなくなってます。てかバグってグリモン動かなくなるのでこれを適用しないでください


LDRizeが使えないのは耐えられないので、Firefox 4.0b10でGreasemonkey 0.9.1のユーザスクリプトのwindowを共通にする改造をグリモンに施した。
LDRizeが使えないことについてはこの辺参照。

あとTombloo使ってる場合はこちらの方法がいいかも
Twitter / @utatane: GMのWindowをsharedにするTombloo ... http://twitter.com/#!/Constellation/statuses/31786122715594752

改造方法

グリモンのソースはここ https://github.com/greasemonkey/greasemonkey
改造パッチはこんな感じ

--- a/components/greasemonkey.js
+++ b/components/greasemonkey.js
@@ -255,6 +255,9 @@ GM_GreasemonkeyService.prototype = {
     var xmlhttpRequester;
     var resources;
     var unsafeContentWin = wrappedContentWin.wrappedJSObject;
+    var sharedWindow = {};
+    sharedWindow.window = sharedWindow;
+    sharedWindow.__proto__ = new XPCNativeWrapper(unsafeContentWin);

     // detect and grab reference to firebug console and context, if it exists
     var firebugConsole = this.getFirebugConsole(unsafeContentWin, chromeWin);
@@ -297,6 +300,7 @@ GM_GreasemonkeyService.prototype = {
                                                 "registerMenuCommand",
                                                 unsafeContentWin);

+      sandbox.window = sharedWindow;
       // Re-wrap the window before assigning it to the sandbox.__proto__
       // This is a workaround for a bug in which the Security Manager
       // vetoes the use of eval.

サンドボックスから見えるwindowを、content Windowをプロトタイプにした普通のオブジェクトにしたて、これをユーザスクリプト間で使い回すわけです。

Firefox 4.0b10ではこれで動いてくれるけど、何故かFirefox 3.6.13では動かない
何故かsharedWindow.window.documentがundefined。多分3.6.13のXPCNativeWrapperあたりのバグだと思う。3.6.13ではGM 0.9.0使えばいいか。

まぁ、とりあえず、こんな方法でどうでしょう?


2010/02/01 追記

Vimperatorユーザなら簡単にLDRizeできるようになるよ

そういえばGMはXPCOMで上記の部分取り出していじれるから、グリモンのソースコードいじってxpiビルドする必要なかった。
Vimperならvimperatorrcに以下を追加するだけで上記パッチあてられる

" Greasemonkey 0.9.1でwindowを共通にする。(必要性は一時的?"
js <<EOM
autocommands.add('VimperatorEnter', '.*',
  function() {
    let gm = Components.classes['@greasemonkey.mozdev.org/greasemonkey-service;1'];
    if (gm) {
      gm = gm.getService().wrappedJSObject;
      if (gm.injectScripts.toSource().search('sharedWindow') == -1) {
          gm.injectScripts = liberator.eval(
              gm.injectScripts.toSource()
                  .replace(/(?=var firebugConsole)/,
                          'var sharedWindow = {};' +
                          'sharedWindow.window = sharedWindow;' +
                          'sharedWindow.__proto__ = new XPCNativeWrapper(unsafeContentWin);')
                  .replace(/(?=sandbox\.__proto__)/, ' sandbox.window = sharedWindow;'),
              gm.injectScripts);
      }
    }
  });
EOM

あとLDRize使うVimperならldrize_cooperation.js使ってると思うので、上記GMの改造にあわせて次のパッチが必要です
すでに以下のパッチは最新版に取り込まれました。最新のldrize_cooperation.jsを使えばおkです。swirhenさんありがとうございます

https://github.com/vimpr/vimperator-plugins/blob/master/ldrize_cooperation.jshttps://github.com/vimpr/vimperator-plugins/blob/master/ldrize_cooperation.js

--- a/ldrize_cooperation.js
+++ b/ldrize_cooperation.js
@@ -184,18 +184,18 @@
                     } else {
                         var [code,codebase,sandbox] = arguments;
                     }
-                    if(sandbox.LDRize != undefined && sandbox.Minibuffer != undefined){
+                    if(sandbox.window.LDRize != undefined && sandbox.window.Minibuffer != undefined){
                         sandbox.window.addEventListener("focus",function(){
-                            self.LDRize = liberator.eval("self",sandbox.LDRize.getSiteinfo);
-                            self.Minibuffer = liberator.eval("command",sandbox.Minibuffer.addCommand);
-                            if (typeof self.LDRize.getSiteinfo != 'function') self.LDRize = sandbox.LDRize;
-                            if (typeof self.Minibuffer.addCommand != 'function') self.Minibuffer = sandbox.Minibuffer.command;
+                            self.LDRize = liberator.eval("self",sandbox.window.LDRize.getSiteinfo);
+                            self.Minibuffer = liberator.eval("command",sandbox.window.Minibuffer.addCommand);
+                            if (typeof self.LDRize.getSiteinfo != 'function') self.LDRize = sandbox.window.LDRize;
+                            if (typeof self.Minibuffer.addCommand != 'function') self.Minibuffer = sandbox.window.Minibuffer.command;
                         },false);
-                        if(window.content.wrappedJSObject == sandbox.unsafeWindow){
-                            self.LDRize = liberator.eval("self",sandbox.LDRize.getSiteinfo);
-                            self.Minibuffer = liberator.eval("command",sandbox.Minibuffer.addCommand);
-                            if (typeof self.LDRize.getSiteinfo != 'function') self.LDRize = sandbox.LDRize;
-                            if (typeof self.Minibuffer.addCommand != 'function') self.Minibuffer = sandbox.Minibuffer.command;
+                        if(window.content.wrappedJSObject == sandbox.window.unsafeWindow){
+                            self.LDRize = liberator.eval("self",sandbox.window.LDRize.getSiteinfo);
+                            self.Minibuffer = liberator.eval("command",sandbox.window.Minibuffer.addCommand);
+                            if (typeof self.LDRize.getSiteinfo != 'function') self.LDRize = sandbox.window.LDRize;
+                            if (typeof self.Minibuffer.addCommand != 'function') self.Minibuffer = sandbox.window.Minibuffer.command;
                         }
                     }
                 });

GMの改造にあわせて、sandboxのところをsandbox.windowにした。