Home > Latest topics

Latest topics 近況報告

たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。

萌えるふぉくす子さんだば子本制作プロジェクトの動向はもえじら組ブログで。

宣伝1。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能! シス管系女子って何!? - 「シス管系女子」特設サイト

宣伝2。Firefox Hacks Rebooted発売中。本書の1/3を使って、再起動不要なアドオンの作り方のテクニックや非同期処理の効率のいい書き方などを解説しています。既刊のFirefox 3 Hacks拡張機能開発チュートリアルと併せてどうぞ。

Firefox Hacks Rebooted ―Mozillaテクノロジ徹底活用テクニック
浅井 智也 池田 譲治 小山田 昌史 五味渕 大賀 下田 洋志 寺田 真 松澤 太郎
オライリージャパン

Page 35/239: « 31 32 33 34 35 36 37 38 39 »

ツリー型タブのタブバーの背景を透明にしたい(How to make the tab bar transparent?) - Oct 26, 2009

Q

In Tree Style Tab extension, would it be possible to make the background (dark gray blank area) display an image? Maybe with a userstyle or script...

ツリー型タブで、タブの背景(暗いグレーの空白の領域)に画像を表示できませんか? ユーザースタイルシートかスクリプトを使えばできると思うんですが……

A

On Firefox 3.6, you'll be able to make the background color of the tabbar transparent, like following CSS in the userChrome.css:

tabbrowser[treestyletab-style][treestyletab-mode]
  .tabs-stack,
tabbrowser[treestyletab-style][treestyletab-mode]
  .tabbrowser-tabs,
tabbrowser[treestyletab-style][treestyletab-tabbar-position]
  .tabbrowser-tabs {
  background: transparent !important;
}

On Firefox 4:

:root[treestyletab-style][treestyletab-tabbar-position]
  #appcontent,
:root[treestyletab-style][treestyletab-tabbar-position]
  tabbrowser,
:root[treestyletab-style][treestyletab-tabbar-position]
  .tabbrowser-strip {
  background: transparent !important;
}

Another way, you can get transparent tab bar with a secret preference "extensions.treestyletab.tabbar.style.aero". Go to "about:config" and turn it to "true".

上記のようなCSSをuserChrome.cssに書くと、タブバーの背景色を透明にできます。1つ目はFirefox 3.6用、2つ目はFirefox 4用の指定です。

また別の方法として、隠し設定「extensions.treestyletab.tabbar.style.aero」でもタブバーを透明にできます。「about:config」を開いて、この設定の値を「true」に変更して下さい。

Webアプリケーションからも利用できるAPIを備えたXUL/Migemoをリリースしたよ - Oct 21, 2009

XUL/Migemo 0.12.xで、機能を他のアドオンとかから呼び出すためのAPIを刷新してみたよ。

古いAPI(はてなブックマーク拡張とかが使ってくれてるやつ)は僕自身が色々よく分からないまま作った物だったために、引数を文字列で渡さないといけないとか戻り値も正規表現オブジェクトではなく文字列だとか、色々と使い勝手が悪かったと思う。メインウィンドウ以外では呼び出す時にいちいちXPConnect使わないといかんし。

新しいAPIは、それに比べたらものっそシンプルになった。XPConnect使わなくてもmigemo.getRegExp('hoge')とか書くだけで使えるし、戻り値もすぐに使える正規表現オブジェクトが返ってくるし。互換性を保つために旧APIはそのまま残してあるので、旧APIを使ってるアドオンが動かなくなるということはないけど、今後は使うなら新APIの方を使うのがお勧めです。

で、このAPIはWebページ内のスクリプトでもCPUの使用率を取得できるようにするAPIを提供する例のアドオンの技術の応用なので、Webページ内のスクリプトからもXUL/Migemoの機能を利用できてしまいます。

ただしスクリプトの実行権限の関係で、上記のmigemo.getRegExp('hoge')のような、正規表現オブジェクトを直に受け取る機能は使えません。代わりにJavaScript/Migemo互換の、正規表現のソース文字列を返すAPI migemo.query('hoge') などを使う必要があります。

XUL/Migemo 0.12.2以降が入ってる環境でこのページを表示してれば、以下のデモを試せるはず。


  • コーヒー
  • 紅茶
  • 緑茶
  • 抹茶
  • コーラ
  • 日本酒
  • ビール

ページ内検索系のメソッドもあるんだけど、多分使いでがなさそうなので解説は用意してないです。

すでに上でもリンクしてるけど、エンジンごとページ内に埋め込めるJavaScript/Migemoという実装もあるから、XUL/Migemoを入れてるFirefoxユーザでないと使えないこのAPIってなんか意味あんの?と言われそう。深くはツッコまないでください。

以下、補足事項。

当初このエントリでは、「Webページ上のスクリプトからもmigemo.getRegExp('hoge')のようにして正規表現を取得して利用できる」という風な書き方をしてたけど、これは大間違いだった。戻り値の正規表現オブジェクトが生成された実行コンテキストがUniversalXPConnect特権のある場所なのに対して、呼び出し元は特権のない普通のWebページ上であるため、それぞれの権限が違うので本来ならその正規表現の各メソッドは実行できないのが正しい。

ただ、Gecko 1.9.1(Firefox 3.5)以前のバージョンにはバグがあって、上記のようなセキュリティのチェックが働かないために、戻り値の正規表現の各メソッドを呼べてしまう状態になっていた。

このバグはGecko 1.9.2(Firefox 3.6)以降ではすでに修正済みで、実際、Trunk等で戻り値の正規表現オブジェクトのメソッドを呼ぼうとすると、その場で処理が中断されて Error: RegExp.prototype.toString called on incompatible ChromeObjectWrapper というエラーがエラーコンソール上に出力される。

ということで、JavaScript/Migemo互換のAPIとして正規表現オブジェクトのソース文字列だけを返すような機能を0.12.2で新たに加えた。文字列や数値などのプリミティブ値に対してはセキュリティのチェックが行われないようなので、こっちはGecko 1.9.2以降でもWeb上で使える。

情報化タブのプログレスバーをいじってみたよ - Oct 08, 2009

Tab Progress BarのプログレスバーがFirefox 3.7のモックアップ風なのを見て「羨ましい!」と思ったのでInformational Tabのデフォルトスタイルをそのように変えてみた。一応、設定で今まで通り(ラベルの下に表示)にも戻せる。

で、やるならとことんやってみっか!と一念発起して、モックアップにあるような光るプログレスバーを再現しようと頑張ってみた。 伸びるバーの部分は背景画像で、ぽわーんと光った感じは-moz-box-shadowを使ってるので、Firefox 3.5じゃないと期待通りには見えない。

匿名顕名実名偽名 - Oct 07, 2009

匿名云々の話になるとどうしても感情的になってしまう。そこに「ネットはバーチャル」「ネットは現実と切り離して好き勝手暴れまくるための掃き溜め」みたいな話が入ってくるとなおのこと。

匿名であることを全面的に非難するとか、実名を明らかにすることを強要するとか、そういう考えは無い。自分も匿名でつぶやくことはあるし。

何に対して激しくアレルギー反応を示してるかって、やっぱり、匿名で安全圏から石投げてくる奴らにイラつかされてきた……という印象があるから、そういうのに対して過敏になってるんだろう。「実名晒すとか馬鹿かよwww俺はネットは便所の落描きにしか使ってないしwwww承認はオフラインで十分得られてるしwwwwお前みたいなウスノロはネットというただの便所にしがみついておこぼれにあずかってろよwwwwホレホレ悔しかったらリア充になってみろよwwwwまあ無理だけどなwwww」みたいに言われてるように感じる。

実名垂れ流しでここまで来た自分が思うこと - Oct 07, 2009

僕が実名をWebで出し始めたのは、Mozilla用の拡張機能のライセンス文に本名を書く必要があるものと思い込んでいたためだった。実際の所、世に溢れるコードを見てみると必ずしも本名でなくても構わないような感じだ、というのはずいぶん後になってから知った。ともかく、まあ、本名を晒し始めたという事実があったわけです。当時僕は何歳だっけ。記録に残ってる一番古いバージョンが2001年9月のリリースだから、ええと、大学1年で19歳の時か。

でも、名前を晒すということは実質的には何の変化ももたらさなかった。

そもそも、大学3年になるまでアルバイトというものをしたことが無く、やってた部活も交流試合があるようなものではなかったので、自分は「リアルの世界」ではほとんど全く社会との繋がりがない、価値のない存在だったと言っていいと思う。学祭の垂れ幕作りだとかそういう所でしか世の主流の人々から存在を意識されることがない、いてもいなくてもどうでもいいような人だった。

そんな僕が他人からとそれなりの価値を認められたのは、漫研の中であり、イラストを公開するために作ったこのサイト(当時はまださくらのレンタルサーバではなくISPの無料スペースだったんだけど)であり、そこでの活動であり、つまり僕にとっては「社会との繋がり」はリアル世界よりもむしろWebが起点になっていた。

なので、アルファベット4文字の「Piro」であろうが漢字4文字の「下田洋志」であろうが、その文字列にはWeb上での僕を識別するためのidentifier以上の意味はなかったわけです。実質的には。Webにあった僕の活動の足跡を粗探ししても、出てくる物はたかが知れてたし。

その後、Mozillaの拡張機能を作っていたことが縁でもじら組のMozilla Partyに呼んでいただけて、その打ち上げの席でグッデイに紹介してもらえて、就職して、クリアコードに籍を移して、「Piroがおるから」という理由で会社にMozilla関係の仕事が舞い込んできたりして、という感じで今に至ってる。

で、この現状が「実名を出してたからこそこうなった」「完全匿名でやってたらこうはいかなかった」という話の例になるのかというと、それが僕には分からない。会社で普通に「ぴろたん」と呼ばれてる事を考えると、実名公開してなくてもこうなってたんじゃないの? と思えてくる。

ただ、活動の最初から今に至るまで一貫して同じ名前でいたからこそこうなったのだろう、という事は言えると思ってる。誉められた事も誉められなかった事も、僕がやってきた事は全部この名前に紐付けられていて、だからこそそれらは「実績」として評価することができるのだろう。identify不能な完全匿名で(毎回別の名前で、とか、「名無しさん」でだけ書き込む、とか)活動していたら、何をしてもそれらはひとまとまりの「実績」として見ることはできなかったのだろう。

そういえば僕は、トロフィーとか盾とか貰ったことがないんすよね。そのくせ、誰かに誉めて欲しがっていた。トロフィーという、「お前のそれは称賛に値するのだ」という目に見える評価がずっと欲しかった。欲しかったけど、手に入れられるはずのない物だ。同人だのCSSだのWeb標準だのMozillaだのという非主流のものを、しかもその世界の中心でガッツリやるんじゃなくて周辺に留まってちまちまやってるだけでは、絶対にそんなもん貰えない。誰もそんなものくれない。中心に飛び込む勇気だとか、マイナー分野じゃなくメジャー分野に転向する勇気だとか、そういうのがなければもう絶対に手に入らない。

でも、そんなマイナー分野の周辺でゴソゴソしてただけの僕でも、今自分の名前でググると何かしら出てくる。作った物への評価、していた事への評価が見つかる。それが今の僕にとってはトロフィー代わりになってるのかもしれない。

人に誉められて悦になりたい、トロフィーを眺めたり人に見せびらかしたりしてニタニタしたい、にもかかわらずその象徴たる「トロフィー」のような物理的な証を絶対にもらえそうにないという人は、ひとつの名前で活動するといいのかもしれない。検索すればそこにトロフィーがあるし、そういう形で人に見せびらかすこともできるのだから。

そういうわけで僕は「実名推進」ではなく「顕名推進」の立場を取らせていただいております次第です。

哀さんの初舞台「飯縄おろし」を観劇してスタンディングオベーション以下略するスレ - Oct 05, 2009

伝説の黒歴史ドキッ! 丸ごとウェブ!! ブラウザだらけの討論大会 ~Chatでユーザのポロリもあるよ~をプロデュースした哀さんは最近演劇に凝っておられるようなのですが、その哀さんがプロの劇団で客演するそうで、見に来るようにというサクラ電波を受信しました。

演劇というと、高校時代に漫研の隣が演劇部で、演劇部の友人からかなりカオスな世界であると聞かされていた(いかにワケの分からないことをするかを競うとかなんとか……)ため、苦手意識があったんですよね。でも食わず嫌いみたいなんですよねよく考えたら。

  • ミュージカルは小学校だか中学校だかの頃に、情操教育の一環か何かで劇団四季に学年全体で招待されて(?)見たことがあって、エンターテインメントとして面白かったので、嫌いではない。マンマ・ミーア!も面白かった。
  • オペラはセリフが全部歌でしかも歌詞が全部英語だかフランス語だかなので全然ついていけなかった。

という感じでミュージカルとオペラは見たことあるけど普通の舞台演劇は意外にも未体験だったようです。なので、いい機会かと思って行ってみることにしました。

哀さん曰く、演じるために5回ほどDVD見て毎回泣いたそうなので、(高校の頃に聞いたカオスな情報とは異なって)普通にお話として楽しめるものなのだと推測しています。以下IRCのログより抜粋。

21:30 (i_Phone) ケータイが無いころの長野県高校三年生が
21:30 (i_Phone) 大雪で学校に閉じ込められて
21:31 (i_Phone) 自分の未来も見えなくて
21:31 (Piro) 一人また一人と消えていく「ケッ、俺は殺人鬼なんかと一緒にいられねえぜ! 部屋に帰らせてもらうぜ!」
21:31 (i_Phone) とりあえず学校の出し物のお芝居、頑張ってやろうよ
21:31 (i_Phone) ちげえw

ということで、このエントリを見た人で7日がヒマな人は一緒に見に行ってみませんか。という宣伝なのでした。

ちなみにその翌日の11月8日はFirefox Developers Conferenceが開催される予定です。僕もなんか話すと思うのでよかったら見に来て下さい。

XPIDLで自作コンポーネントのインターフェースを定義する時に気をつけないといけないこと - Oct 01, 2009

XUL/MigemoがTrunk(3.7a1pre)で動かなくなっていた件について原因を調べてた。

エラーの原因

エラーメッセージに見覚えがあるなあと思って検索したら、前に書いたエントリがヒットした。

一個だけ躓いた所として、XPCOMコンポーネントの新しいメソッドをIDL定義に追加して引数にnsISelectionController型のオブジェクトを渡すようにしていた所、XPIDLでのコンパイルは通るんだけど実際に使う時にNS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFOというエラーが出てにっちもさっちもいかなくなってしまった。ダメ元で、引数の型をnsISupportsにして受け取り側でQueryInterfaceするようにしてみたところ、ちゃんと動いてくれた。一体何だったんだろうこれは。

ああ、前にも詰まってたところだったか……この時は結局「理由」が分からないままで、とりあえず動くようにはなったからということでそれ以上は調べなかったんだよね。

改めて検索してみたら、似たような問題にぶち当たった人がいたようだった。で、やっと何が問題の原因だったのかが分かった。

新しいXPCOMコンポーネントを定義する時に、インターフェースも新しく定義する場合、XPIDLを使ってインターフェースを定義してやらないといけない。

[scriptable, uuid(4aca3120-ae38-11de-8a39-0800200c9a66)]
interface xmIXMigemoFileAccess : nsISupports
{
   AString getAbsolutePath(in AString filePath);
   AString getRelativePath(in AString filePath);
   AString getExistingPath(in AString absoluteOrRelativePath);
   AString readFrom(in nsIFile file, in ACString encoding);
   nsIFile writeTo(in nsIFile file, in AString content, in ACString encoding);
};

この時、メソッドの引数や返り値の型として、AStringやlongのようなプリミティブ型(?)だけでなく、nsIFileのように他のインターフェースを使うこともできる。

この時気をつけないといけないのが、インターフェースには2つの識別子があるということ。1つは、上記の例でいえばinterface xmIXMigemoFileAccessという部分で定義されているインターフェース名「xmIXMigemoFileAccess」、もう一つは[scriptable, uuid(4aca3120-ae38-11de-8a39-0800200c9a66)]という部分で定義されているインターフェースID(IID)「4aca3120-ae38-11de-8a39-0800200c9a66」だ。

今回は、XUL/Migemoのコンポーネントの機能のうち、nsIDOMRangeやnsIDOMWindowを値の型として使っていた部分でエラーが起こっていた。

interface xmIXMigemoTextUtils : nsISupports
{
   (略)
   AString range2Text(in nsIDOMRange range);
   (略)

具体的にはこの辺。どうも、Firefox 3.5から3.7a1preまでの間のどこかの時点で、nsIDOMRangeやnsIDOMWindowのIIDが変更されたらしい。XPIDLのコンパイル(.xptファイルの生成)には成功しても、そのあと3.7a1preのFirefoxが.xptを解釈する時に、IIDの方でnsIDOMRangeやnsIDOMWindowのインターフェース定義を探すために、「こんなIIDのインターフェースは定義されてないよ! インターフェースの情報が見つからないよ!」というエラーになっていたようだ。

とぴあさんに色々教えてもらった。元々、XPCOMの元になった(?)COMの世界つまりC++の世界では、インターフェースの識別にはIIDを使うのが原則というかIIDこそが本来の識別子で、nsIDOMRangeとかの名前はそれへの参照に過ぎないということなのだそうな。

インターフェースの内容が変化した時(メソッドの追加等)には、「古いインターフェースの定義が消されて、別のIIDで新たなインターフェースが定義された」というような扱いになるようだ。「IIDが変わった」と前述しているけれども、プログラム的には「IIDが変わっただけで同じインターフェース」なのではなく「全くの別物」という扱いだから、全く互換性は保証されない……というわけ。

なお、互換性を維持したままインターフェースに新しい機能を追加するためには、現在使われているインターフェースの定義はそのまま残して、それを継承した新しいインターフェースを定義する必要があるということになる。「nsIPrefBranch2」とか「nsIGlobalHistory3」などがそれにあたる。

回避策

nsIDOMRangeやnsIDOMWindowのIIDが3.7a1preのものと同じになっている新しいSDKを使って.xptファイルを作り直してやれば、3.7a1preでもXUL/Migemoが動くようになるはず。でも、そうすると今度はFirefox 3.5以下で動かなくなる。それは困る。

無難な解決策は、値の型として使うインターフェースを、古いFirefoxから新しいFirefoxまでの間でずっと変わっていないインターフェースにするということ。nsISupports(すべてのXPCOMの基底インターフェース)ならほぼ確実に使える。

interface xmIXMigemoTextUtils : nsISupports
{
   (略)
   AString range2Text(in nsISupports range);
   (略)

このようにインターフェースの定義を変えた上で、実装の方で受け取った値をQueryInterface()してやる。

range2Text : function(aRange) {
   aRange.QueryInterface(Ci.nsIDOMRange);
   var doc = aRange.startContainer;
   (略)

こうすると、メソッドを呼ぶ時に、DOMのRangeオブジェクトをそのまま引数に渡せる状態を維持できる。

JavaScriptのレイヤからはIIDではなくヒューマン・リーダブルなインターフェース名だけを使うのが一般的なのだけれども、こうしておけばXPCOMのフレームワークが自動的に「新しいIIDのnsIDOMRangeインターフェース」を参照してくれる。実際にインターフェースで定義されている内容には変更が起こっているかもしれないから、確実な動作は保証できなくなるけれども、当該のインターフェースが「既にある機能はなくなったり変更されたりせず、新しい機能が追加されていくだけ」という傾向があるのなら、おおむね問題なく動作し続けてくれると考えられる。

そもそも……

とぴあさんが調べてくれたのだけれども、今回のトラブルの原因になったnsIDOMRangeは定義の頭の方に@status FROZENと書かれていて、本来であれば、IIDが変わることもなければメソッドやプロパティなどのインターフェース定義の内容が変わることもない、安心して永続的に使えるインターフェースだったはず……のようだ。

それが、Bug 396392 – Support for getClientRects and getBoundingClientRect in DOM Rangeに提出されたパッチでメソッドが追加されると同時にIIDも変更されてしまった。本当は、これはあってはならない事態らしい。当該バグのコメントでもnsIDOMRangeのIIDは元に戻して、変更はnsIDOMNSRange(Geckoの独自拡張の機能が色々定義されているインターフェース)に対して行うべきと書かれている。おそらく近いうちに、nsIDOMRangeのIIDは元の物に戻されて、XUL/Migemoが動かなくなってしまった問題も解消されるものと思われる。

個人的な感覚としては、インターフェースに変化が無くても実装が変わって挙動も変わりました……なんて事がMozillaではザラにあるので、インターフェースの部分でだけ「ちょっとでも変化があったらIIDは別の物! インターフェースとしても別物!」という風に厳密に区別しても意味なくね? と思う。ぶっちゃけ、「安心して使えるAPI」なんてのはMozillaの世界じゃリップサービスに過ぎないと思ってる。(とぴあさんには、それはプロジェクトのマネジメントがマズイという別のレイヤの問題だよねと言われた。)

あと、現在のFirefox(Gecko 1.9以降)では、自分で新しくインターフェースを定義してXPCOMコンポーネントを作る必要はほとんど無いと言っていい。JavaScriptでコンポーネントを定義してJavaScriptだけから使うのであれば、JavaScriptコードモジュールを使えばよくなった。また、起動直後に処理を行うような場合なんかには相変わらずXPCOMコンポーネントの定義が必要だけど、それは既存のインターフェース(nsISupportsやnsIObserver)だけでも事足りる。XPIDLが必要になるのは、JavaScriptで書かれた機能をC++のレイヤから呼び出したいような時だけだ。普通に開発する分には、こんな事で悩む必要は今や全くない。という事に気がついて、今更になって激しい徒労感を感じている。

ツリー型タブでセッション復元時にツリーが壊れる問題について調査中 - Sep 29, 2009

表題の件について、どーも実際に表示されてる内容とセッション情報とが食い違ってるケースがあるようだ。

Firefoxのタブとかのセッション情報はJSONっぽい文字列で保存されてて、最初はJSON整形で読みやすい形にして調べようと思ってたけど、めんどすぎたので、以下のようなスクリプトでツリー構造の所だけ可視化してみた。

var sv = gBrowser.treeStyleTab;

var session = sv.SessionStore.getWindowState(window);
eval('session = '+session);

var result = [];

session.windows[0].tabs.forEach(function(aInfo) {
   var entry = aInfo.entries[aInfo.entries.length-1];
   var item = {
         label    : entry.title+' / '+entry.url,
         id       : aInfo.extData[sv.kID],
         children : (aInfo.extData[sv.kCHILDREN] || '').split('|'),
         parent   : (aInfo.extData[sv.kPARENT] || ''),
         items    : []
      };
   var bullet = '*';
   var tab = sv.getTabById(item.id);
   if (tab.getAttribute(sv.kPARENT) != item.parent) {
      item.label += '\n<WRONG PARENT>';
      bullet = '?';
   }
   if (tab.getAttribute(sv.kCHILDREN) != item.children.join('|')) {
      item.label += '\n<WRONG CHILDREN>';
      bullet = '?';
   }
   item.label = item.label.replace(/^/gm, '  ').replace(/^./, bullet);
   var current, index;
   if (result.some(function(aItem) {
         if (!aItem) return false;
         if (aItem.items.some(arguments.callee)) return true;
         current = aItem;
         index = aItem.children.indexOf(item.id);
         return index > -1;
      })) {
      if (current.items.length <= index) {
         while (current.items.length < index) current.items.push(null);
         current.items.push(item);
      }
      else {
         current.items[index] = item;
      }
   }
   else if (result.some(function(aItem) {
         if (!aItem) return false;
         if (aItem.items.some(arguments.callee)) return true;
         current = aItem;
         return aItem.id == item.id;
      })) {
      current.items.push(item);
   }
   else {
      result.push(item);
   }
});

var string = result.map(function(aItem) {
      var children = aItem.items.map(arguments.callee).join('\n');
      return children ?
            aItem.label+'\n'+children.replace(/^/gm, '  ') :
            aItem.label ;
   }).join('\n')+'\n';

alert(string);

で、調べてみたら、やっぱりツリー構造がおかしい。ツリー表示はタブの属性値の方に基づいて行われてて、その属性値をnsISessionStoreのsetTabValue()deleteTabValue()でセッションの方にミラーしてるんだけど、ミラーされてるはずの値が期待通りにミラーされてないようだ。

追記。

……nsSessionStore.jsを読んでたら原因が分かった。

  • setTabValue()では内部で最後にsaveStateDelayed()を呼んでいるため、変更がファイル(プロファイルフォルダ内のsessionstore.js)にすぐ書き出される。
  • deleteTabValue()ではsaveStateDelayed()が呼ばれてないために、他の処理の中でsaveStateDelayed()が呼ばれるまでは変更がファイルに書き出されない。
  • ファイルが書き出されないうちにFirefoxを終了したり再起動したりすると、メモリ上のセッション情報は破棄されて、ファイルに書き出されたセッション情報が次回起動時に読み込まれる。
  • よって、deleteTabValue()だけで情報をミラーしたつもりでいると、ゴミ情報が残ったままになってしまうことが多々ある。そのゴミ情報が邪魔をして、期待通りにツリー構造が復元されなくなってしまっている。
  • 調べてみたらBug 510965 - deleteWindowValue and deleteTabValue API functions need to call saveStateDelayedというバグも立っていた。

deleteTabValue()する前にsetTabValue()で空の値をセットして強制的にセッション情報を書き出させるようにしてみたところ、上記のスクリプトで調査してもセッション情報との間でのツリー構造の不整合は検出されなくなった。

結論:deleteTabValue()マジ使えねえ……

追記。

それでも全然駄目だった。Firefoxがセッション情報をファイルに書き出す時、読み込み中であるというフラグが立っている(Firefox 3.5以前ではtab.linkedBrowser.parentNode.__SS_data._tabStillLoading、Firefox 3.6以降ではtab.linkedBrowser.__SS_data._tabStillLoadingtrueである)タブについてはキャッシュされた情報を書き出すようになってるのに、このフラグがタブの内容の読み込み完了後も立ちっぱなしになってるせいで、常にキャッシュされた古い情報が書き出されてしまい、setTabValue()で設定された新しい値が無視されてしまう。

結論:nsISessionStore/nsSessionStore.jsは腐ってる……

まとめると、以下のようなメソッドを使うようにしてやれば色々と幸せになれそうです。

setTabValue : function(aTab, aKey, aValue) {
   if (!aValue) return this.deleteTabValue(aTab, aKey);

   try {
      this.checkCachedSessionDataExpiration(aTab);
      this.SessionStore.setTabValue(aTab, aKey, aValue);
   }
   catch(e) {
   }

   return aValue;
},

deleteTabValue : function(aTab, aKey) {
   try {
      this.checkCachedSessionDataExpiration(aTab);
      this.SessionStore.setTabValue(aTab, aKey, '');
      this.SessionStore.deleteTabValue(aTab, aKey);
   }
   catch(e) {
   }
},

checkCachedSessionDataExpiration : function(aTab) {
   var data = aTab.linkedBrowser.__SS_data || // Firefox 3.6-
              aTab.linkedBrowser.parentNode.__SS_data; // -Firefox 3.5
   if (data &&
       data._tabStillLoading &&
       aTab.getAttribute('busy') != 'true' &&
       aTab.linkedBrowser.__SS_restoreState != 1)
      data._tabStillLoading = false;
},

2010年1月29日追記。Firefox 3.6以降とFirefox 3.5以前でフラグが保存される場所が少し違っていたので、その旨を修正した。

2010年9月27日追記。Firefox 4 の最適セッションリストア原文)の影響によって、まだ実際にはセッションが復元されていないタブなのに、ビジー状態でなくなっているというケースがあり得るようになった。そのため、aTab.getAttribute('busy')だけでビジー状態を判別すると、これからセッションを復元して欲しい・読み込み中のタブであるにも関わらず_tabStillLoadingをfalseにしてしまい、セッションが復元されなくなってしまうという問題が起こっていた。なので、タブの属性値と併せてaTab.linkedBrowser.__SS_restoringも確認するようにサンプルコードを修正した。

2010年12月6日追記。aTab.linkedBrowser.__SS_restoringが廃止されてaTab.linkedBrowser.__SS_restoreStateというプロパティが使われるようになっていたので、それにあわせてサンプルコードを修正した。

GARDEN PARTY お茶会 2009 Autumn - Sep 28, 2009

新宿マルイワン主催?のお茶会イベントが27日にマルイ本館屋上の庭園で開催されてまして、hknさんが2枚チケットを貰ったけど一緒に行く人のアテがなかったということで、ついて行ってみました。

イベントの中身としてはロリィタなブランドのファッションショーがメインと事前に告知されてたそうなので、そこに僕が混ざり込んでも大丈夫なのか?!と大変不安だったため、事前にパンク系ブランドの服(Sixh. ふわふわもさもさパーカ CMD4-Z808 BK-GY/M)をhknさんに見立ててもらいました。でもあとで分かりましたがフツーの服の人もちらほらいたので、そこまで気張らなくてもよかったようです。まあ買っちゃった以上は今後も着ますけど。先日の1983の飲み会でも着ました。

  • 11時頃にマルイ前に着いた時点で、既に結構な人数のロリィタさんがいました。列待機でもしてるのか?と思ったら、単に一緒に行く予定の友達との待ち合わせとかそういうのだったようです。
  • ロリィタさん大集合の図に驚いてか、白人旅行者っぽい人達が写真を撮ってた気がします。
  • 僕がそこで待ってる間にも参加者らしきロリィタさんがだんだん集まってきてたんですが、彼女が比較的ライトなロリィタ・彼氏が普通の服装(ロリィタでもパンクでもない、フツーの。本当にフツーの。)という組み合わせの参加者らしきカップルがやってきた時に、その様子を見てちょっと戸惑ってたように見えたのがワロけました。
  • hknさんはハーフウィッグに帽子をかぶって登場。読者モデルの深澤翠さんが来る、ということでアイメイクは本人曰く「100%中の100%」だそうです。恋する乙女はすごいですね。

で、入場。

  • 屋上庭園でお茶会てどんなんだと思ったら、芝生の上にシートが敷かれてその上にイスがステージに向けて沢山並べられてて(あと通路沿いにも丸イスが沢山並べられてた)、様相としてはほんとにファッションショーがメインなんだなというのがよく分かる感じでした。
  • こういうイベントは初の開催らしくて、オペレーションが微妙に手慣れてない感が漂っていたような気がします。客席から見て左の方を指して「(ステージから見て)右手の方に……」とアナウンスしてたりとか。
  • 軽食が出てました。小さなサンドイッチ2個とお菓子1個(組み合わせにはバリエーションがあったみたい)の組み合わせで、サンドイッチのうち1個が思いがけずカレー味で、ナマステ・インディア2009(代々木公園で開催されてたインドフェス)に行った翌日にまたカレーかよ!と自分でツッコんでしまいました。
  • モデルさんが通路の所を歩いて庭園をぐるっと1周してましたが、通路沿いの席にいると間近で見れて圧巻でした。皆さんかわいかったです。
  • ファッションショーはAngelic PrettyBABY,THE STARS SHINE BRIGHTmetamorphose temps de filleの3ブランドで、それぞれブランドごとにモデルさん5人が順番に出てきて最後に全員でまた1周する、という感じでやってました(読者モデルの深澤翠さんAMOさん、ルナさんの3人と、各ブランドのショップ店員さん2名という組み合わせ)。翠さんのブログに一部の衣装の写真があります
  • APの時、翠さんがhknさんに手を振ってました。いつも綺麗な写真を撮ってくれる某方と記憶されてるようです。
  • BABYの時、最後の「全員で1周」の時に最後にもう一人増えてて「なんだこれ」と思ってたらゲストライブのKaya様でした。「誰か混ざったのか? ハプニング?」とか思ってすみませんでした。
  • 記念に一緒にKERAスナップをとhknさんが言ってくれてましたが、Kaya様ライブが終わった段階でスナップの受け付けが終了してしまって、撮れずじまいでした。大変無念です。
  • 結構気合い入った女装子じょそこの人がいてびびりました。確認できただけでも最低2人はいたようですね。
  • 会場をざっと見て、改めて「うん、hknさんはかわいい」と思いました。(←超失礼)
  • おみやげにお菓子を貰いました。帰宅後に食べました。おいしかったです。(速攻で食べたので写真無し)
  • イベントのアンケートに回答して、デコリョーシカ学習帳をもらいました。どう使えばいいんですかこんなの。
  • 読者モデルの人とのスナップ撮影みたいなプログラムがなかったことをhknさんが残念がっていました。

ロリィタのことはよく分かりませんが、かわいい衣装(読者モデルの人もめちゃめちゃかわいかった)を沢山見れて面白かったです。写真はhknさんのレポートに期待ということで。→hknさんのレポ

addTab, loadOneTabの引数がFirefox 3.6で変わる? - Sep 16, 2009

trunk gBrowserのloadOneTabとaddTabの引数が変わった - alice0775のファイル置き場 - Yahoo!ジオシティーズを見て初めて知ったけど、TrunkでgBrowser.addTab()gBrowser.loadOneTab()の仕様が変わったようだ。

すでに追加されている「現在のタブの隣に新しいタブを開く」機能は、リファラが渡されていれば現在のタブの隣に、そうでなければタブバーの右端にタブを開くという挙動になっている。これに対し、リファラを渡さなくても現在のタブの隣に新しいタブを開けるようにしたい、という要望が出た(当然と言えば当然だ)。

それを実現するには、普通に考えると、gBrowser.addTab()gBrowser.loadOneTab()の引数でそういう挙動を指定できるようにしてやらないといけない。しかしどっちのメソッドもすでに多数の引数を受け付けるようになってて(現状でもすでに6個ある!)、これ以上引数を増やすのってどうなん? と。関数の引数が多いのは悪い設計の典型例だ。こういう場面ではハッシュなりなんなりを使うのが定石ですわな。そこで件のバグが立ったと。

最初に提出されたパッチは、引数リストにさらにaRelatedToCurrentを加えつつ、各引数に対応する値をプロパティに持つオブジェクトを2番目の引数として渡した時はそっちを使うようにするという風になってる。これだけ見ると「また引数増やすのかよ、しかも新方式(ハッシュによる指定)もサポートするのかよ。マンドクセ。」と思うところだけど、2番目に提出されたパッチでは引数の数の方は変更が無くて、aRelatedToCurrentに相当する引数を指定したい時はハッシュを使わなければならないようになってる。実際にチェックインされた内容は後者のパッチの通りだ。

この事から、今後は新方式のAPI(新しいタブの挙動はgBrowser.addTab()gBrowser.loadOneTab()の第2引数でハッシュで指定する)が標準となり、旧方式のAPI(gBrowser.addTab()gBrowser.loadOneTab()に沢山の引数を渡す)はあくまで後方互換性のためにのみ残されている、という風に考えることができる。

参考までに、新旧それぞれの書き方を示しておこう。

// new API
var newTab = gBrowser.addTab('http://www.example.com/', {
               referrerURI          : referrer, // nsIURI
               charset              : 'Shift_JIS',
               postData             : null,
               inBackground         : true,
               allowThirdPartyFixup : false,
               relatedToCurrent     : false
             });

// old API
var newTab = gBrowser.addTab(
               'http://www.example.com/',
               referrer, // nsIURI
               'Shift_JIS',
               null, // postData
               true, // inBackgorund
               false // allowThirdPartyFixup
             );

本当だったらもっと早く、Firefox 3.0になる前の時点でこういう事は済ませておくべきだったんだろうと思う(そのための「メジャーバージョン」でしょ?)。でもまあ、いつかはやらなきゃいけないことだ。新しい引数が追加されるというタイミングは、移行のいいきっかけではある。

Page 35/239: « 31 32 33 34 35 36 37 38 39 »

Powered by blosxom 2.0 + starter kit
Home

カテゴリ一覧

過去の記事

1999.2~2005.8

最近のつぶやき

オススメ

Mozilla Firefox ブラウザ無料ダウンロード