wine
Visual
XShape
XPutImage
FIXME

Inside Wine; 未整理、色々

More than 1 year has passed since last update.

目次


Inside Wine; 未整理、色々


結論から

Linux の WINE では、親が Desktop の Window、即ち、OVERLAPPED WINDOW (TITLE BAR を持つ) または、POPUP WINDOW (TITLE BAR を持たない) だけが、X Window System の Window であり、それ以外のウィンドウ、即ち、WS_CHILD 属性を持つような Window は、X Window の Window ではなく、WINE が自前で描画している擬似的な Window のようです。

その場合、「surface」なる構造体を必ず持ち、LineTo や、TextOut などでの描画関数では、surface の pixel 配列にドットの色の値を書き込みます。メッセージキューが Idle であるような場合に x11drv_surface_flush() や、update_surface_region() なる関数呼び出されます。そこで、最後に、XShmPutImage() または、XPutImage() が行われ、XFlush() されます。つまり、子 Window への描画は、即座には画面に反映されず内部バッファに蓄積されるだけで、基本的には、時間に余裕がある時にのみ、画面に反映されることになります。この結果、メッセージ・キューに未処理のメッセージがありつづける場合、画面へは滅多に反映されません。これは Windows とは異なります。Windows の場合は、同じ状況の時は、WM_PAINT は後回しになりますが、その場合でも、LineTo() などの描画関数は、どんなタイミングであってもとにかく使ったならば、ほぼその瞬間に画面に反映されますから。WM_PAINT のハンドラ自体に時間がかかっている場合は、Windows では、WM_PAINT のハンドラ内で描画して行く様子はそのままリアルタイムに反映され続けますが、WINE だと、必ずしもそうはならない事があると思われます。


LineTo() の実際の実装

LineTo( hdc, x, y ) は、


~/wine/dlls/gdi32/painting.c

/***********************************************************************

* LineTo (GDI32.@)
*/

BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
{
DC * dc = get_dc_ptr( hdc );
PHYSDEV physdev;
BOOL ret;

TRACE( "%p, (%d, %d)\n", hdc, x, y );

if(!dc) return FALSE;

update_dc( dc );
physdev = GET_DC_PHYSDEV( dc, pLineTo );
ret = physdev->funcs->pLineTo( physdev, x, y );

if(ret)
{
dc->cur_pos.x = x;
dc->cur_pos.y = y;
}
release_dc_ptr( dc );
return ret;
}


のようになっている。ここで、上記の関数ポインタ physdev->funcs->pLineTo は、Linux の X Window、Mac、Android などの環境を切り替える場合にも利用されるが、環境が、Linux の X Window 環境に限定されていても、一意的に決まっているわけではなく、以下の様に色々な関数ポインタに変わり得るらしい:

X11DRV_LineTo   // 基本

PSDRV_LineTo // PostScript driver の場合
MFDRV_LineTo // meta file の場合
EMFDRV_LineTo // Enhanced MetaFile driver の場合
dibdrv_LineTo // DIB driver の場合 :
windrv_LineTo // Driver for window surfaces
pathdrv_LineTo // Graphics paths (BeginPath, EndPath etc.) の場合

dwExStyle に WS_EX_LAYERERD を指定して、完全透明色を利用した透明ウィンドウの場合、これが、windrv_LineTo になることが分かっている。

なお、windrv_LineTo は、surface の lock と unclock で挟む以外は、dibdrv_LineTo を呼び出しており、surface をロックする以外は、本質的に後者と同じ事を行う。

update_dc() は、それまでに dc->dirty が 1 になっていたら、

dc->hookProc( dc->hSelf, DCHC_INVALIDVISRGN, dc->dwHookData, 0 );

を呼び出す。hookProc は、デフォルトでは、dc_hook() 関数らしい。

dc_hook() は、code = DCHC_INVALIDVISRGN の時、ほぼ、

update_visible_region( dce ); を呼び出す。

dc->dirty は、GetDC の直後には 1 になっているらしい。

update_dc() を呼び出した後は、0 になるらしい。


Visual C++ の WINE へのインストール

英語版のインストールは、成功し、かつ、アプリのビルドまで可能である。

インストールは、WineHQ のやり方に従う必要がある。

日本語版は、インストールはできたが、アプリのビルドは出来なかった。ビルドを命じると、ビルド開始のメッセージが出て何のエラーも出ないが、実は何もコンパイルされない。

なお、英後版インストールの場合、環境変数の LANG に英語を指定した。

そのままだと、WINE 上で Wz エディタを起動したときに、文字化けするので、また、LANG を日本語用に直す。


トレース表示(デバッグ表示)

結論から言えば、以下のいずれかで行ける:

1. FIXME( "hwnd = %08X\n", hwnd );

2. fprintf( stderr, "Xxxx(), hwnd = %08X\n", hwnd );

「1.」の方は、自動的に行頭にファイル名と関数名が付与される。ただし、改行コードの「\n」が必要なので注意。

「2.」の方も、普通に使える。ただし、かならず、stderr に出力し、stdout は、不用意に使ってはならない。実際に使ってみると、WINE で Windows アプリの起動時に、そのコマンドライン引数に、printf() した文字列がそのまま渡されてしまうらしいから。

名称からすると、「TRACE()」 を使うべきようにも思うかもしれないが、それはデフォルトでは、画面に何も出てくれないし、表示させるための設定の複雑さから、使うのは意外と難しい。環境変数に色々設定しないといけないし、単純に ENABLE に設定すると既に書かれている大量の TRACE() が大量に表示されてしまい、自分が書いたものが識別できないことになる。だから、特定の物だけを ENABLE にしなくてはならないが、新規参加者(?)には難しい。


・・・/wine/libs/wine にライブラリ関数を追加したい場合

・・・/wine/libs/wine/wine.map

に間数名を追加する必要がある。

そうしないと、ライブラリを使う側からリンク(参照)できない。


フォルダ構成


1. /wine/libs/wine

libwine.so.1.0 # ELF 形式の共有ライブラリ, loader など。

libwine.so.1 -> libwine.so.1.0

libwine.so -> libwine.so.1.0


2. /wine/dlls/user32

user32.dll.so # ELF 形式の共有ライブラリ

user32.dll.fake # 偽者の DLL


3. /wine/dlls/winex11.drv

winex11.drv.so # ELF 形式の共有ライブラリ

(↑ X Window 用の「ドライバ」)

winex11.drv.fake # make で生成される。

winex11.drv.spec # spec ファイル。make で更新されにくい。


4. ・・・/wine/

wine -> tools/winewrapper


5. ・・・/wine/tools

winewrapper # Wrapper の シェルスクリプト

(↑Wrapper script to run Wine and Winelib apps from inside the source tree)


1.に関して

本体は、libwine.so.1.0 であるが、WINE 起動時に実際に探されるファイル名は、libwine.so.1 らしい。そのため、

$ ln libwine.dll.so.1.0 libwine.dll.so.1

の意味でのリンクが用意されている。wine は、dll.so.1.0 ではなく、dll.so.1 の方を探すのである。この性質を利用すると、dll.so の検索パスを「偽装」して、make install しないで済ますことができることがある。


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


aaa

あああ


end