Hatena::Groupmoz-addon

hogezilla RSSフィード

当ページに書かれているコードは、修正BSDライセンスのもと、再頒布して頂いて構いません。

2013-05-22

Firefox 24 で browser.__SS_restoreState が削除された

| 21:18 | はてなブックマーク - Firefox 24 で browser.__SS_restoreState が削除された - hogezilla

これまで、起動時等のタブは前のセッションから回復しているが、コンテンツはまだロードされていない状態を示すフラグ的プロパティとして、browser.__SS_restoreState というプロパティに1が入ってた。そして、ロードされた後は、このプロパティは削除されるという挙動であった。

が、このバグで、__SS_restoreStateプロパティは使用されなくなる。

代わりに、nsISessionStore.isTabStateNeedsRestore(browser) を使用して真偽値を得るように変更された。


before after

before

var browser = gBrowser.browsers[i];
if ("__SS_restoreState" in browser) {
  // not restored yet
}

after

const sessionStore = Cc["@mozilla.org/browser/sessionstore;1"].getServices(Ci.nsISessionStore);
var browser = gBrowser.browsers[i];
if (sessionstore.isTabStateNeedsRestore(browser)) {
  // not restored yet
}

参考

Firefox 23 で browser.__SS_data が削除された

| 21:17 | はてなブックマーク - Firefox 23 で browser.__SS_data が削除された - hogezilla

これまで、browser.__SS_dataにタブのセッションデータを得ることができたが、削除されてしまった。

代わりに、きちんとnsISessionStore.getTabState(tab)を使用しないといけない。

const sessionStore = Cc["@mozilla.org/browser/sessionstore;1"].getServices(Ci.nsISessionStore);
var tab = gBrowser.tabs[i];
var tabState = JSON.parse(sessionStore.getTabState(tab));
トラックバック - http://moz-addon.g.hatena.ne.jp/teramako/20130522

2012-09-13

“can’t access dead object” エラーを体験する

| 21:29 | はてなブックマーク - “can’t access dead object” エラーを体験する - hogezilla

Firefox 15 からコンテンツがアンロードされたとき、コンテンツ内のデータ(例えばDOM要素)へのリファレンスが強制的に削除されるようになった。これによりメモリに不用意に残り続けていたものが消えて省メモリ化しますよ、となったわけだ。

そして、削除されたオブジェクトのプロパティにアクセスしようとすると、“can’t access dead object”のエラーが出るようになった。

これをワザと出してみようと試みた。

体験するためにスクラッチパッドを使用する。

  1. about:config から devtools.chrome.enabledtrue にする。
  2. スクラッチパッドを起動する
  3. 実行環境メニューから「ブラウザ」を選ぶ
  4. 以下を記入して実行
var tab = gBrowser.loadOneTab("about:blank", { inBackground: false });
tab.linkedBrowser.addEventListener("load", function(e){
    this.removeEventListener("load", arguments.callee, true);
    var doc = this.contentDocument;
    gBrowser.removeTab(tab);
    setTimeout(function(){
        Cu.reportError(doc.title);
    }, 2 * 1000);
}, true);

エラーコンソールに以下の様にでるはず。

時刻: 2012/09/13 21:25:39
エラー: TypeError: can't access dead object
ソースファイル: Scratchpad
行: 7

上記では、var doc = this.contentDocument と Documentオブジェクトへの参照を保持するようにしたが、DOM要素以外でも、var obj = new this.contentWindow.wrappedJSObject.Array("a","b")等の普通のJSオブジェクトでも構わない。

2012-02-07

拡張機能と単体アプリとして起動の両立

| 00:02 | はてなブックマーク - 拡張機能と単体アプリとして起動の両立 - hogezilla

単なるメモ


単体アプリとして起動

firefox -app /path/to/application.ini

と、-appオプションを付けると、XULRunner的な単体アプリとして起動が可能である。

(注意:フルパスである必要があると思う)

XULRunnerで起動とは違い、Firefox独自のXPCOMとかJavaScript CodeModuleが使えたりして、XULRunnerだと面倒そうな事が簡単にできたりして便利。


困ったこと

ただ、困ったこともある。

UA

拡張と違い、単体アプリとして起動するので、ベンダーやバージョン情報などがapplication.iniに依存することとなり、結果ユーザーエージェントがFirefoxとは違うことになる。

通常だと、以下の様になる。

Mozilla/5.0 (Windows NT 5.1; rv:10.0) Gecko/20100101 VendorName/VenderVersion

今回は、Firefox内にある、orionエディタを使用したかったのだが、このorionのコードが、Firefoxであるかどうかをユーザーエージェントをみて分岐している。エンジンはFirefoxGeckoそのものなのでFirefoxとして判断して欲しい。

resource URL

Firefox内のコードモジュールを import しているところを見ていくと

  • resource:///modules/....jsm
  • resource://gre/modules/....jsm

と2つの書き方をしている。

通常ならば、どちらも同じ場所を示すのだが、-appの単体アプリとして起動させた時は別の場所を示す。

  • resource:///modules/ の場合は、application.iniのあるディレクトリ/modules/
  • resource://gre/modules/ の場合は、Firefoxインストールディレクトリ/omni.ja

となる。Firefoxの資源はそのまま使用したいし、このままではモジュールをインポートできなかったというエラーが出ることになる。

以下の様なコードを書けば確認できる。

const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resouce://gre/modules/Services.jsm");
(function(){
  var resProtocolHandler = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResPorotocolHandler);
  log("resource:///   : " + resProtocolHandler.getSubstitution("").spec);
  log("resource://gre/: " + resProtocolHandler.getSubstitution("gre").spec);
})();

解決方法

UA

これは、defaults/prefereces/pref.js

pref("general.useragent.compatMode.firefox", true);

を追加すると、UAが以下の様に変化して Firefox/10.0 が追加されて無事解決できた。

Mozilla/5.0 (Windows NT 5.1; rv:10.0) Gecko/20100101 Firefox/10.0 <var>VendorName</var>/<var>VenderVersion</var>
resource URL編

こちらは、正直微妙な解決方法であり、推奨できるやり方ではないかもしれない。ということを始めに書いておく。

まず、Firefoxには、components/nsBrowserGlue.js というJavaScriptで書かれたXPCOMがあり、プロセス起動時真っ先に動くようになっている。(XPCOMcategory app-startup nsBrowserGlue service,@mozilla.org/browser/browserglue;1 として登録されている)

このXPCOMは起動してくると、resource:///modules/distribution.jsを import するlazyGetterを作る。

これは -app オプションで単体起動させると、起動アプリ側のmodulesディレクトリを見に行くので通常ならば存在しないファイルとなる。

そして、final-ui-startupのオブザーバーイベント*1が通知された時に、imporしたオブジェクトのメソッドを呼ぶ。

ここにリソース位置を変更するコードを書いておいてやれば、ウィンドウが立ち上がる前に設定変更ができる。

var EXPORTED_SYMBOLS = [ "DistributionCustomizer" ];

const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
const DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC = "distribution-customization-complete";

function DistributionCustomizer() {}
DistributionCustomizer.prototype = {
  _bookmarksApplied: false,
  applyBookmarks: function () {
    this._bookmarksApplied = true;
    this._checkCustomizationComplete();
  },
  _prefDefaultsApplied: false,
  applyPrefDefaults: function () {
    this._prefDefaultsApplied = true;
    this._checkCustomizationComplete();
  },
  _customizationsApplied: false,
  applyCustomizations: function () {
    this._customizationsApplied = true;

    var resProtocolHandler = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService)
                              .getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
    resProtocolHandler.setSubstitution("", resProtocolHandler.getSubstitution("gre"));
    this._checkCustomizationComplete();
  },
  _checkCustomizationComplete: function () {
    if (this._bookmarksApplied && this._customizationsApplied) {
      let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
      os.notifyObservers(null, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC, null);
    }
  },
};

applyCustomizationsメソッドがfinal-ui-startup時に呼ばれるので、

var resProtocolHandler = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService)
                          .getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
resProtocolHandler.setSubstitution("", resProtocolHandler.getSubstitution("gre"));

と、空文字列のresourceを登録しなおしてやれば良い。

トラックバック - http://moz-addon.g.hatena.ne.jp/teramako/20120207

2011-09-21

トラックバック - http://moz-addon.g.hatena.ne.jp/teramako/20110921

2011-07-07

Firefox 8.0a1 で「孤立タブ」の存在が消えた

| 23:26 | はてなブックマーク - Firefox 8.0a1 で「孤立タブ」の存在が消えた - hogezilla

おそらく、Firefox 8.0a1 からだが、Bug 654721により、「孤立タブ」の存在がなくなった。

「孤立タブ」ってのは自分が勝手に呼んでいるだけなんだけど、以下の様なもの。

孤立タブ
グループに属さない孤立したタブ。(パノラマビューからタブをドラッグ&ドロップでグループ外へドロップすると作れる)
Firefox4 のタブグループとタブ

以前であれば、パノラマのビューからタブをグループ外に放り出すと、この「孤立タブ」を作ることができた。が、上記Bugが修正されたことで、放り出しても新たなグループ内に属するように修正されている。

コード上の問題

今までなら、下記の様にして「孤立タブ」を取得していたが、getOrphanedTabs()は削除されている。

// window をパノラマのビュー内のwindowオブジェクトとする
var tabItems = window.GroupItems.getOrphanedTabs();

独自にパノラマ関連コードを書いている人はご注意あれ。

また、Bug 632294で、UI.setActiveTab(tabItem)もなくなっている。代わりに以下を使用すると良い。

window.UI.setActive(tabItem);

UI.setActive(tabItem)GroupItems.setActiveGroupItem(groupItem), 旧UI.setActiveTab(tabItem)を兼ねる存在なので、以前はこの2つを実行する必要があったが、1つで良くなっている。

自分の作っている拡張ではIssues - teramako/Pano - GitHubの #10, #11 でこの問題を解決させている。ご参考までに。

トラックバック - http://moz-addon.g.hatena.ne.jp/teramako/20110707