宣伝。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。
以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能!
Chromeウィンドウでは、window.open()
やwindow.openDialog()
の第3引数でalwaysRaised
フラグを指定することで、「常に最前面に表示」状態のウィンドウを開くことができる(通常のスクリプトではこのフラグを使うには特権が必要)。じゃあ、すでに開かれているウィンドウを最前面にすることはできないのか? というのが今日のお題。
フォクすけクロックを使ってみて、Firefoxのウィンドウの下に時計が隠れてしまうのは不便きわまりないと思ったので、これをどうにかしたかった。最初は、前述のalwaysRaised
を使った方法でいけるかなと思ったんだけど、Firefoxのアドオンとして動作する時はこれでいいけどXULRunnerアプリとして動作する時には「開く元の親ウィンドウ」が無いからこれじゃダメだ、と気がついた。
んでちょっと調べてみた所によると、どうもnsIXULWindowインターフェースのzLevel
というプロパティをいじることで、ウィンドウの重ね合わせの優先順位を動的に変更できるようだということが分かってきた。
以下のようにいくつかのインターフェースを経由することで、Chromeウィンドウ(nsIDOMWindow)からnsIXULWindowのインターフェースに辿り着くことができる。
var Ci = Components.interfaces;
var XULWindow = window
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIXULWindow);
XULWindow.zLevel = Ci.nsIXULWindow.raisedZ;
zLevel
に指定可能な値はnsIXULWindowインターフェースにおいて定数プロパティとして定義されていて、以下の種類がある。
プロパティ | 実際の値 | 意味 |
---|---|---|
Ci.nsIXULWindow.lowestZ | 0 | すべてのウィンドウの最背面 |
Ci.nsIXULWindow.loweredZ | 4 | すべてのChromeウィンドウの最背面 |
Ci.nsIXULWindow.normalZ | 5 | 通常 |
Ci.nsIXULWindow.raisedZ | 6 | すべてのChromeウィンドウの最前面 |
Ci.nsIXULWindow.highestZ | 9 | すべてのウィンドウの最前面 |
lowestZ
とloweredZ
の違いは、前者がエクスプローラその他Windowsネイティブのアプリケーションのウィンドウも含めてすべての最背面になるのに対して、後者はあくまでFirefoxのウィンドウの中での最背面になるだけであるということ。loweredZ
を指定したChromeウィンドウが他のネイティブアプリのウィンドウの下にある時、そのChromeウィンドウをクリックすると、そのChromeウィンドウがネイティブアプリのウィンドウの上に表示されるようになると同時に、それに「押し上げられる」形で、FirefoxのウィンドウすべてがそのChromeウィンドウより前面に表示される。
highestZ
とraisedZ
もそれと同様に、後者を指定したウィンドウは上にネイティブアプリのウィンドウが重なりうるけど、前者にはいかなるウィンドウも上には重ならない……のかと思いきや、こちらはどっちを指定してみてもraisedZ
で期待される通りの挙動にしかならなかった(Firefoxのウィンドウの中での最前面になるだけで、他のネイティブアプリのウィンドウが前面にくると、その下に隠れてしまう)。これってバグ?
ちなみに、数値で1~3を指定した場合はloweredZ
(4)を指定したのと同じ挙動になるようだ。多分7~8はraisedZ
(6)と同じで、それ以上はすべてhighestZ
(9)と同じになるんだろうと思うけど……前述の通りhighestZ
とraisedZ
は実際の挙動に違いが全然無いので、それを確認することはできなかった。
あと、ずっと前にEz Sidebarでこの問題にぶち当たってから気になってるもののずっと直ってないみたいなんだけど、raisedZ
以上が指定されたウィンドウがあると、通常のウィンドウで開いたモーダルダイアログが親ウィンドウの下に潜ってしまうという問題が起こる。パスワードの入力を求めるダイアログ等がFirefoxのウィンドウの下に潜ってしまって使い物にならないので、これはマジで困る。どうにかならんものだろうか。
――ということで対策を考えてみた。
var XULWindow = window
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIXULWindow);
var observer = {
observe : function(aSubect, aTopic, aData)
{
if (aTopic == "xul-window-registered") {
XULWindow.zLevel = Ci.nsIXULWindow.normalZ;
window.setTimeout(function() {
XULWindow.zLevel = Ci.nsIXULWindow.highestZ;
}, 250);
}
}
};
var ObserverService = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService);
ObserverService.addObserver(MakeOnTopObserver,
"xul-window-registered", false);
新しいウィンドウが開かれる直前にウィンドウのzLevel
を元に戻して、ウィンドウが開かれた後にまた最前面に戻す。こうすれば最後の問題は回避できる。
の末尾に2020年11月30日時点の日本の首相のファミリーネーム(ローマ字で回答)を繋げて下さい。例えば「noda」なら、「2007-09-26_zlevel.trackbacknoda」です。これは機械的なトラックバックスパムを防止するための措置です。
writeback message: Ready to post a comment.