マルチモニタ環境でウィンドウが画面外にはみ出すのを防止


最近はディスプレイも安いので, ディスプレイを複数台並べて広い作業環境を確保している人も多いはず. うちの自宅環境も, 24インチワイドディスプレイの隣に21.5インチワイドディスプレイを縦置きにしている. 縦置きする理由は, Webブラウザを最大化表示してなるべくスクロールせずに済ますため, 論文などA4サイズのPDFを1画面におさめるため, など. この環境自体には大変満足しているけれど, 少々変則的な配置のため特定のアプリケーションのウィンドウが画面外に表示されてしまって難儀した. それをなんとかしたという話.

困りどころ

Linuxのサーバ上で起動したアプリケーションのウィンドウを, マルチモニタ環境のWindows上のXmingで表示したときに問題が起きた. 問題が起きるのは一部のアプリケーションの一部のウィンドウだけで, たとえばInkscapeでPDFファイルを開いたときの"PDF Import Settings"というウィンドウなどが, 問答無用で画面外に出てしまう.

Windowsのマルチモニタ環境では, 仮想的なスクリーンとして, すべてのディスプレイの画面を覆うような矩形を作るようになっている. たとえばうちの環境では, 1920x1200の画面の右隣に1080x1920の画面があり, それを覆う3000x2363の領域が仮想スクリーンになっている.

当然, 仮想スクリーンの内側であっても実際のディスプレイの外側になっている部分もあり, とくに問題なのは, 仮想スクリーンの左上端がディスプレイの外だということ. そのことをアプリケーション側が認識せずに, とにかく左上端に表示することがあるようで, そうすると当然ディスプレイ外に出てしまう.

ちなみに, 縦置きのディスプレイが左側にあれば, 左上端はディスプレイ上なので問題は起きない. けれど残念なことに, うちの環境では部屋の配置の都合で縦置きディスプレイを右側にするしかないので, 困った.

解決策

いろいろ検討した結果, ウィンドウをすべて監視して, 画面外のウィンドウを強制的に画面内に移動させる常駐アプリを作った. デフォルトではウィンドウの表示・移動・サイズ変更のタイミングで画面外に出ていたら強制的に連れ戻す(オプションで移動に関知しないようにもできる).

作ったアプリケーション

http://up.orezdnu.org/release/mmwnd.zip

mmwnd.exe
アプリ本体(32ビットWindows用)
mmwndhook.dll
mmwnd.exeが使用するので同フォルダに入れること
mmwnd64.exe
アプリ本体(64ビットWindows用)
mmwndhook64.dll
mmwnd64.exeが使用するので同フォルダに入れること
README.ja.txt
使い方

64ビットのWindowsで64ビット/32ビットどちらのアプリケーションも監視してほしい場合はmmwnd.exeとmmwnd64.exeの両方を起動しておけば可能.

テスト環境

Windows Vistaはテストできなくもないけれど面倒なので確認していない. たぶん動く.

ソースコード


mminfo
マルチモニタの情報を表示するツール
mmwnd
ウィンドウを監視して画面外から連れ戻すアプリ
与太話

なぜかmminfoはRubyで書いた. dl/importべんり. 本当はmmwndもRubyで書きたかったけれど, SetWindowsHookExを使うためにDLLを作る必要があり, Rubyでは大変そうだったので久しぶりにC++で書いた. もっと久しぶりにWindowsアプリを作った.

マルチモニタ関係ないけれど, Windows 7でタスクバーを上に表示して, 縦幅を画面ぎりぎりいっぱいに設定しておいたPuTTYを起動すると, タイトルバーがタスクバーの裏に隠れてしまって困ったりしたので, それも解消されて地味に嬉しい.

事前に調べたこと

実は, ウィンドウ同士をぴったりくっつけて並べるMagnetWindow (Vector, 作者サイト)というツールに, 「デスクトップからはみださない」という類似の機能がある. ただし, mmwndと比べて少なくとも以下の点が異なる.

  • アプリケーションが新たに作ったウィンドウが最初からはみ出している場合は何もしない
  • マルチモニタ環境では「タスクバーにかぶらない」オプションを有効にできない
  • (少なくともマルチモニタ環境では)はみ出さないようにする範囲は, 仮想スクリーンの内側