Home > Latest topics

Latest topics > nsIFocusManagerを使ってウィンドウを最前面に持ってくる方法

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

nsIFocusManagerを使ってウィンドウを最前面に持ってくる方法 - Jun 24, 2011

Firefox上でいくつかのサブウィンドウを開いていて、それらのウィンドウすべてがワンセットで他のウィンドウより前に出てきていて欲しい場面、というのがある。

例えば、GIMPはツールボックス等が複数のウィンドウにばらけている。これがもし、画像を編集するウィンドウにフォーカスしたらツールボックスのウィンドウがその背後に隠れてしまうという風になっていると、まるで作業にならないだろう(古いバージョンのGIMPをWindowsで使った時にはそんな風になってて頭を抱えた記憶がある)。

また、そういうワンセットで表示されていて欲しいウィンドウ達が、同時に起動している他のアプリケーションのウィンドウの前と後ろにそれぞればらけてしまうというのも、使う時に地味にうざい。

Firefoxの上で、拡張機能が開くウィンドウでGIMPのウィンドウ群のような振る舞いをさせるにはどうすればよいのか。このエントリでは2つの方法を紹介する。

まず1つ目。nsIXULWindowインターフェースのzLevelプロパティを使うと、Firefoxのプロセスが開くウィンドウの重ね合わせの順序をある程度制御する事ができる。一番単純なやり方は、ウィンドウを一時的に最前面表示に切り替えて、その後すぐに元に戻す、という方法だろう。

var XULWindow = window
                .top
                .QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsIWebNavigation)
                .QueryInterface(Ci.nsIDocShellTreeItem)
                .treeOwner
                .QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsIXULWindow);

var originalZIndex = XULWindow.zLevel;
XULWindow.zLevel = Ci.nsIXULWindow.highestZ;
window.setTimeout(function() {
    XULWindow.zLevel = originalZIndex;
}, 0);

ただ、仕様上の制限のため、この方法はWindowsでしか使えない。少なくともUbuntu 10.04のGnomeでは機能しなかった。

代わりに考えられるもう1つのやり方が、フォーカスを使うやり方だ。単純に考えても、window.focus()でウィンドウにフォーカスを与えると、強制的にそのウィンドウを最前面に持ってくる事ができる。

しかしこの方法にも問題がある。普通にwindow.focus()すると、例えばそのウィンドウの中の特定のテキストボックスにフォーカスしていたとしても、そのフォーカスが失われてしまう事になる。

この問題を回避するには、Gecko 1.9.2/Firefox 3.6から導入されたフォーカスマネージャを使わないといけない。具体的には以下のようにする。

var FocusManager = Cc['@mozilla.org/focus-manager;1']
                   .getService(Ci.nsIFocusManager);

// 現在フォーカスされている要素を取得する。
// 第1引数:検索する最上位のDOMWindow
// 第2引数:再帰的な検索を行うかどうかのフラグ(trueを渡す)
// 第3引数:その要素が含まれているフレームのDOMWindowを
//          受け取るためのスロットとなるオブジェクト
var focusedWindow = {};
var focusedElement = FocusManager.getFocusedElementForWindow(window, true, focusedWindow);

// 現在のフォーカスが何によって与えられたかの情報を取得する。
var reason = FocusManager.getLastFocusMethod(focusedWindow.value);

// フレームにフォーカスする。
focusedWindow.value.focus();

// フォーカスされていた要素がある時は、その要素にもフォーカスする。
if (focusedElement) {
    // フォーカスを与える時に、スクロール状態等に変更を加えないように指定する
    let flags = Ci.nsIFocusManager.FLAG_RAISE |
                Ci.nsIFocusManager.FLAG_NOSCROLL |
                Ci.nsIFocusManager.FLAG_NOSWITCHFRAME |
                reason;
    FocusManager.setFocus(focusedElement, flags);
}

こうすれば、Linuxでも要素のフォーカス状態を失わせずにウィンドウを最前面に持って来れる。ウィンドウのフォーカスを動的に切り替えるため、その都度各ウィンドウが画面上でぺかぺか点滅してしまう(一瞬だけフォーカスされて、その直後にフォーカスが失われるため)、というデメリットはあるが。

分類:Mozilla > XUL, , , , , , 時刻:15:46 | Comments/Trackbacks (0) | Edit

Comments/Trackbacks

TrackBack ping me at


の末尾に2020年11月30日時点の日本の首相のファミリーネーム(ローマ字で回答)を繋げて下さい。例えば「noda」なら、「2011-06-24_frontmost.trackbacknoda」です。これは機械的なトラックバックスパムを防止するための措置です。

Post a comment

writeback message: Ready to post a comment.

2020年11月30日時点の日本の首相のファミリーネーム(ひらがなで回答)

Powered by blosxom 2.0 + starter kit
Home

カテゴリ一覧

過去の記事

1999.2~2005.8

最近のコメント

最近のつぶやき