This SIAP application is revealing more problems with Wine. This time it is the reason for the original complaint: Mr. Maximiliano Curia reported that in the version of Wine he could test, the treeview control in the middle of the screen was not updated correctly. The treeview control should have looked like this:
+---------------------------------+ |Persona Física | | | | | +- Datos identificatorios | | | | | | | +- Nombre y otros datos | | | +- Domicilio | | | +- Actividades | | +- Datos comerciales | | | | | | | +- Datos de interés fiscal| | | +- Claves bancarias | | +- Responsable por deuda ajena | +---------------------------------+
Don't mind the actual meaning of the text in the nodes. The problem is that for Mr. Curia, the treeview control actually shows up like this:
+---------------------------------+ |Persona Física | | | | | | | | | | | | | | | | | | | | | | | +---------------------------------+
That is, the treeview control only shows the first line of the tree. After some digging in the treeview control, I saw that the code in the control tries to save some drawing by querying the update region of the control window. When the WM_PAINT message indicates a non-null HDC in wParam, the code fetches the update region for the control window. If I understand the intent of the code correctly, the WM_PAINT message can be sent to the control with an wParam of the HDC of an offscreen bitmap, in order to draw the tree into it. When the update region of the control is NULL, the code fetches the BITMAP structure of the target HDC in order to clip the drawing to the dimensions of the target bitmap.
The problem is that, in the case of the treeview managed by COMCTL32.OCX, for some as yet undiscovered reason, the control *always* has a null update region, except for the very first rendering (which is overwritten by a second rendering with the problematic null region). No matter how the window is uncovered, the update region remains null. Therefore, the control believes that the target is an offscreen bitmap, even for the rendering to the screen. It then fetches the default bitmap selected, which is an 1x1 dummy bitmap, gets a 1x1 target region, and believes that only 1 pixel should be updated. Only the very first item gets redrawn because of this.
The following patch works around this issue. However, this is not a proper fix, because the control window should have been properly invalidated in the first place, and the control should therefore have a proper update region. I am not really sure whether the root cause is in the treeview code or in the region updating code. I am inclined to the former, because the same treeview control seems to work correctly in regedit.exe:
--- wine-20050930-cvs/dlls/comctl32/treeview.c 2005-09-12 17:34:07.000000000 -0500 +++ wine-20050930-cvs-patch/dlls/comctl32/treeview.c 2005-10-02 22:08:08.000000000 -0500 @@ -2790,6 +2790,8 @@ RECT rect = *rc; TREEVIEW_ITEM *wineItem;
+ TRACE("refreshing on (%ld,%ld)-(%ld,%ld)\n", rect.left, rect.top, rect.right, rect.bottom); + if (infoPtr->clientHeight == 0 || infoPtr->clientWidth == 0) { TRACE("empty window\n"); @@ -2859,6 +2861,12 @@ rc.left = 0; rc.top = 0; rc.right = bitmap.bmWidth; rc.bottom = bitmap.bmHeight; + if (bitmap.bmWidth == 1 && + bitmap.bmHeight == 1 && + bitmap.bmWidthBytes == 2) { + ERR("failed to recover a valid update region, using GetClientRect()\n"); + GetClientRect(infoPtr->hwnd, &rc); + } TREEVIEW_EraseBackground(infoPtr, (HDC)wParam); } }
The sample (VisualBasic) code and executable have been uploaded as testcases for the following bug report: http://bugs.winehq.org/show_bug.cgi?id=3476
BTW: what happened to the patch that fixes the DBGRID32.OCX control? (Subject: OLEAUT32: add additional condition for creation of interface)
On an (hopefully) unrelated note, the user32 tests are failing, at least on my machine:
../../../tools/runtest -q -P wine -M user32.dll -T ../../.. -p user32_test.exe.so sysparams.c && touch sysparams.ok sysparams.c:1182: Test failed: lfHeight: got -16 instead of 0 sysparams.c:1183: Test failed: lfWidth: got 0 instead of 400 sysparams.c:1185: Test failed: lfWeight: got 400 instead of 7471169 sysparams.c:1186: Test failed: lfItalic: got 0 instead of 105 sysparams.c:1187: Test failed: lfStrikeOut: got 0 instead of 97 sysparams.c:1190: Test failed: lfOutPrecision: got 0 instead of 108 sysparams.c:1193: Test failed: lfQuality: got 0 instead of 32 make: *** [sysparams.ok] Error 7 ../../../tools/runtest -q -P wine -M user32.dll -T ../../.. -p user32_test.exe.so win.c && touch win.ok fixme:win:WIN_CreateWindowEx Parent is HWND_MESSAGE win.c:2213: Test failed: message 0200 available win.c:2221: Test failed: message 000f available win.c:2229: Test failed: message 000f available win.c:2240: Test failed: message 000f available win.c:2248: Test failed: message 000f available win.c:2256: Test failed: message 000f available win.c:693: Test failed: window rect does not match: style:exstyle=0x94000000:0x00000000, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x94000000:0x00000000, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x15c00000:0x00000100, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x15c00000:0x00000100, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x14c00000:0x00000100, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x14c00000:0x00000100, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x14c00000:0x00000100, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x14c00000:0x00000100, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x14c80000:0x00000100, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x14c80000:0x00000100, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x14c40000:0x00000100, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x14c40000:0x00000100, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x14c20000:0x00000100, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x14c20000:0x00000100, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x14c10000:0x00000100, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x14c10000:0x00000100, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x14d00000:0x00000100, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x14d00000:0x00000100, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x14e00000:0x00000100, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x14e00000:0x00000100, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x94000000:0x00000200, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x94000000:0x00000200, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x14c40000:0x00000300, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x14c40000:0x00000300, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x94000000:0x00000080, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x94000000:0x00000080, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x14c40000:0x00000180, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x14c40000:0x00000180, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x94000000:0x00000000, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x94000000:0x00000000, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x14c40000:0x00000100, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x14c40000:0x00000100, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x94000000:0x00040000, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x94000000:0x00040000, menu=1 win.c:693: Test failed: window rect does not match: style:exstyle=0x14c40000:0x00040100, menu=1 win.c:718: Test failed: synthetic rect does not match: style:exstyle=0x14c40000:0x00040100, menu=1 make: *** [win.ok] Error 42 make: Debido a los errores, el objetivo `test' no se reconstruyó.
Alex Villacís Lasso wrote:
This SIAP application is revealing more problems with Wine. This time it is the reason for the original complaint: Mr. Maximiliano Curia reported that in the version of Wine he could test, the treeview control in the middle of the screen was not updated correctly. The treeview control should have looked like this:
+---------------------------------+ |Persona Física | | | | | +- Datos identificatorios | | | | | | | +- Nombre y otros datos | | | +- Domicilio | | | +- Actividades | | +- Datos comerciales | | | | | | | +- Datos de interés fiscal| | | +- Claves bancarias | | +- Responsable por deuda ajena | +---------------------------------+
Don't mind the actual meaning of the text in the nodes. The problem is that for Mr. Curia, the treeview control actually shows up like this:
+---------------------------------+ |Persona Física | | | | | | | | | | | | | | | | | | | | | | | +---------------------------------+
That is, the treeview control only shows the first line of the tree. After some digging in the treeview control, I saw that the code in the control tries to save some drawing by querying the update region of the control window. When the WM_PAINT message indicates a non-null HDC in wParam, the code fetches the update region for the control window. If I understand the intent of the code correctly, the WM_PAINT message can be sent to the control with an wParam of the HDC of an offscreen bitmap, in order to draw the tree into it. When the update region of the control is NULL, the code fetches the BITMAP structure of the target HDC in order to clip the drawing to the dimensions of the target bitmap.
The problem is that, in the case of the treeview managed by COMCTL32.OCX, for some as yet undiscovered reason, the control *always* has a null update region, except for the very first rendering (which is overwritten by a second rendering with the problematic null region). No matter how the window is uncovered, the update region remains null. Therefore, the control believes that the target is an offscreen bitmap, even for the rendering to the screen. It then fetches the default bitmap selected, which is an 1x1 dummy bitmap, gets a 1x1 target region, and believes that only 1 pixel should be updated. Only the very first item gets redrawn because of this.
The following patch works around this issue. However, this is not a proper fix, because the control window should have been properly invalidated in the first place, and the control should therefore have a proper update region. I am not really sure whether the root cause is in the treeview code or in the region updating code. I am inclined to the former, because the same treeview control seems to work correctly in regedit.exe:
--- wine-20050930-cvs/dlls/comctl32/treeview.c 2005-09-12 17:34:07.000000000 -0500 +++ wine-20050930-cvs-patch/dlls/comctl32/treeview.c 2005-10-02 22:08:08.000000000 -0500 @@ -2790,6 +2790,8 @@ RECT rect = *rc; TREEVIEW_ITEM *wineItem;
- TRACE("refreshing on (%ld,%ld)-(%ld,%ld)\n", rect.left, rect.top,
rect.right, rect.bottom);
- if (infoPtr->clientHeight == 0 || infoPtr->clientWidth == 0) { TRACE("empty window\n");
@@ -2859,6 +2861,12 @@ rc.left = 0; rc.top = 0; rc.right = bitmap.bmWidth; rc.bottom = bitmap.bmHeight;
if (bitmap.bmWidth == 1 &&
bitmap.bmHeight == 1 &&
bitmap.bmWidthBytes == 2) {
ERR("failed to recover a valid update region, using
GetClientRect()\n");
GetClientRect(infoPtr->hwnd, &rc);
}} TREEVIEW_EraseBackground(infoPtr, (HDC)wParam); }
The sample (VisualBasic) code and executable have been uploaded as testcases for the following bug report: http://bugs.winehq.org/show_bug.cgi?id=3476
Further testing with native vs. builtin comctl32 show that native treeview (which works correctly) does NOT issue a GetUpdateRect() in response to a WM_PAINT message with a wParam=someHDC. This suggests that native comctl32 knows that a non-null wParam means that the tree must be painted anyway, regardless of whether the control window might have an update rect. The attached patch gets rid of the (incorrect?) extra GetUpdateRect() call and does a GetClientRect() on the control window instead to get a working bounding rect. This fixes the bug for the sample app in bug 3476.
Changelog: * Do not issue a GetUpdateRect() to query an update region for WM_PAINT(wParam=HDC) case. Instead, use GetClientRect() for a bounding rect.
Alex Villacís Lasso