サブディスプレイ上でアウトライン解析ダイアログのドロップ先矩形の描画が正しく行われない
問題内容
アウトライン解析ダイアログをサブディスプレイで表示していると、タイトルバーをドラッグしてダイアログのウィンドウを動かす際にウィンドウの枠の位置に表示されるべき矩形の描画が適切な大きさにならない場合が有ります。
メインディスプレイとサブディスプレイの 拡大縮小とレイアウト の設定値が同一でない設定の場合に発生します。
再現頻度
常に
問題のカテゴリ
- プログラムの動作上の問題
- ローカルビルド版
環境情報
- OS バージョン
- サクラエディタバージョン
- PC情報
サクラエディタ v2.4.2.0 64bit dev Alpha Version
(GitHash 96cf722e173567c19a626bea30cc34c37c629b02)
(GitURL [email protected]:sakura-editor/sakura.git)
Compile Info: V_A641929 WPR WIN601/I800/C000/N601
Last Modified: 2021/7/25 12:36:07
メインディスプレイ : 3840 x 2160, 200% サブディスプレイ : 1080 x 1920, 175%
スクリーンショット

この現象はプロジェクトのプロパティを変更する事で解消する事を確認しました。
Visual Studioの言語設定が English の場合
Manifest Tool > Input and Output > DPI Awareness の設定を High DPI Aware から Per Monitor High DPI Aware に変更
Visual Studioの言語設定が 日本語 の場合
マニフェスト ツール > 入出力 > DPI 認識 の設定を 高い DPI 認識 から モニターごとの高い DPI 認識 に変更
visual studioの操作は、埋め込みマニュフェストの生成オプションを指定する方法かと思います。
変えてもいいんじゃない?に一票。
Per-Monitor DPI Awareness にきちんと対応するとなると、色々と自前でやらないといけない事が多くなりそうです。
基本的には WM_DPICHANGED メッセージに対応する必要があるようです。
https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows#per-monitor-and-per-monitor-v2-dpi-awareness
https://docs.microsoft.com/en-us/windows/win32/hidpi/wm-dpichanged
このメッセージは下記のイベントで送信されるようです。
- ウィンドウが異なるDPIのモニター上に移動された時
- ウィンドウを表示しているモニターのDPIが変更された時
従来の System DPI Awareness の場合は、表示スケール値が異なるディスプレイにウィンドウを移動した場合はウィンドウのビットマップ(これはWDDMで扱うDirectXのサーフェイス的なウィンドウ表示画像という意味合いだと思う)を拡大縮小して表示するとの事です。試しに表示スケールが100%のディスプレイから175%のディスプレイにウィンドウを移動させると表示スケールの比率に合わせてウィンドウが拡大して表示されますが、クライアントエリアがぼけた表示になりました。
Per-Monitor DPI Awareness にきちんと対応するアプリでは、WM_DPICHANGED メッセージを受け取ったら新しいDPIに合わせてウィンドウの表示(基本的にはクライアントエリアに表示するコントロールの位置やサイズ、あとフォントサイズとかもかな?)を調整する必要が出てくるようです。
Most UI frameworks used by desktop applications (Windows common controls (comctl32), Windows Forms, Windows Presentation Framework, etc.) do not support automatic DPI scaling, requiring developers to resize and reposition the contents of their windows themselves.
MSの公式ドキュメントにはこう書かれていました。適当に訳してみますと、
デスクトップアプリが使っている殆どのUIフレームワーク(comctl32, Windows Forms, WPF, 等)は自動DPIスケールに非対応なので開発者がウィンドウ上のコンテンツのリサイズや再配置を自分で行う必要があります。
という事のようです。で、具体的にじゃあ comctl32 にダイアログを作ってもらっているサクラエディタではどう実装すれば良いのかというとMSの公式ドキュメントにサンプルコードがありました。
https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows#example
WM_DPICHANGED メッセージが送られてきたタイミングで子コントロールを列挙して、DPIに合わせてリサイズしたり再配置したり、という事ですね。そういう対処を色々なダイアログやウィンドウの実装に追加して対応するとなると大変な作業量になってしまいます。
その手間を考えると System DPI Awareness のままで良いかな…と思いました。
Per-Monitor DPI Awarenessにきちんと対応するとなると、色々と自前でやらないといけない事が多くなりそうです。
はい、それを分かったうえで、とりあえずマニュフェストだけかえちゃいましょう、も是かな、とw
メリット ・このissueに上がった通り、一部の挙動はそれだけで解消される。 デメリット ・ https://github.com/sakura-editor/sakura/issues/1712#issuecomment-886216054 で上がった通り、「ちゃんと対応する」には結構大変。
ダイアログ描画は、うまくやればまとめて対応できそうです。 大変なのは、ダイアログじゃなくて自前で描いてる(≒オーナードローな)部分の対応なのかな、と。
課題があるのは横目で見つつ、とりあえず変えてみるのはアリだと思います。
はい、それを分かったうえで、とりあえずマニュフェストだけかえちゃいましょう、も是かな、とw
そうした場合にどういう事が起きうるかを考えてみました。
とあるユーザーがメインディスプレイとしてDELLのUP3218Kを使っているとします。そのモニターは31.5インチでネイティブ解像度が7680 x 4320なので、Windowsのディスプレイ設定の表示スケールは400%に設定されています。そしてそのユーザーのサブディスプレイのスペックが19インチで解像度が1280 x 1024で表示スケールが100%に設定されていたとします。この動作環境だと、サクラエディタのウィンドウをメインディスプレイからサブディスプレイに移動したときに、本来表示されるサイズより縦横それぞれ4倍の大きさで表示される事になります。これではダイアログによってはサブディスプレイの画面に収まらないかもしれません。
上記の例はちょっと極端だと思いますが、本来 Per-Monitor DPI Awareness の場合に行うべき処理を省いた場合には発生しうる事です。なのでmanifestの設定をデフォルトでそれに変更するのはちょっと気が引けます。10年後ぐらいには8Kモニタもお手頃価格で買えるようになっているかもしれないですね。
Windows 8.1 以降で使える SetProcessDpiAwareness 関数をアプリの初期化処理時に呼ぶことで挙動を変えられるようなので、設定で System DPI Awareness もしくは Per-Monitor DPI Awareness のどちらにするかを変えられるようにするのが良いかもしれないと思いました。