Hello, I've been investigating defect 11562, and would appreciate some thoughts on how to move forward...
Basically the application creates a new visible window (eg at 0,0 - 200,50) and then draws in it by: 1. BeginPaint - This sets up the cliprgn to the whole window 2. Works out some sizes... 3. MoveWindow - This moves the window to an appropriate place on the screen 4. FillRect (DrawText, EndPaint) to empty the window... From this call (and all follow on ones) nothing is written to the window because although the visible region is correctly calculated, the clip region was not updated by the MoveWindow call.
This highlights 2 problems..
1. MoveWindow doesn't update the DCEx clip_region region, and hence when the visible region changes, it is merged with the clip region and since there is no overlap the visible region is empty so all subsequent processing ends.
Q: Whats the best way to handle that - I was tempted to reset the clip_region to the visible_region (as MSDN sort of implies - you cant really query them so tests don't help much here) in a movewindow call
2. I then hacked MoveWindow to do nothing, so I could progress...
What I see then is the popup is drawn, emptied and framed etc, and THEN overwritten with grey. Debugging this shows the application does not respond to WM_PAINT calls for the popup window - ie its drawn once and once only. You can see this on windows if you alt+tab to a covering window, and then back again. HOWEVER, on windows the popup does display correctly the once
Investigating the cause, all is ok until the trace:event:process_events Expose for hwnd/window 0xd50026/220002c This drives the trace:win:RedrawWindow 0xd50026 rect (0,0)-(250,50) flags: RDW_INVALIDATE RDW_ERASE RDW_ALLCHILDREN and *bang*, all the drawing which has been done is lost
Q: This is getting way outside my understanding of X events, but shouldn't the Expose event for the child (popup) window be processed before returning from CreateWindow with style WS_VISIBLE?
All suggestions welcome - I don't mind writing tests etc but would like to try to come up with a solution for the problem as well!
Jason
"Ann & Jason Edmeades" us@edmeades.me.uk writes:
- MoveWindow doesn't update the DCEx clip_region region, and hence when the
visible region changes, it is merged with the clip region and since there is no overlap the visible region is empty so all subsequent processing ends.
Q: Whats the best way to handle that - I was tempted to reset the clip_region to the visible_region (as MSDN sort of implies - you cant really query them so tests don't help much here) in a movewindow call
You can query the visible region, so with well-chosen dimensions and clip region it shouldn't be too hard to write test cases. Make sure you test both GetDCEx with an explicit clip region and BeginPaint, the behavior is probably different
Q: This is getting way outside my understanding of X events, but shouldn't the Expose event for the child (popup) window be processed before returning from CreateWindow with style WS_VISIBLE?
The way we hack around the asynchronous events is by checking for expose events in UpdateWindow, but of course if the app doesn't even use that it won't help. And on a slow connection the expose events will always arrive too late anyway. We'd need to explicitly wait for the event, but that would hurt badly on slow connections.
Thanks Alexandre,
(BTW This createwindow / movewindow / draw to window is all occurring in LBUTTONDOWN processing)
- MoveWindow doesn't update the DCEx clip_region region, and hence when
the
visible region changes, it is merged with the clip region and since there
is
no overlap the visible region is empty so all subsequent processing ends.
Q: Whats the best way to handle that - I was tempted to reset the clip_region to the visible_region (as MSDN sort of implies - you cant
really
query them so tests don't help much here) in a movewindow call
You can query the visible region, so with well-chosen dimensions and clip region it shouldn't be too hard to write test cases. Make sure you test both GetDCEx with an explicit clip region and BeginPaint, the behavior is probably different
The difficulty here is the inability to directly query the concealed (within the struct DCE) clip_rgn not the visible region. For example, GetClipRgn returns dc->hClipRgn, whereas the dce clip_rgn is internal to user32 painting.c. The only call I can see replaces the region with GetDCEx?
What kind of test did you have in mind - The only idea I had was something like CreateWindow at 100,100, begin paint, MoveWindow to 50,50, FillRect into red, endpaint, then read it back to see if it really is read?
Q: This is getting way outside my understanding of X events, but
shouldn't
the Expose event for the child (popup) window be processed before
returning
from CreateWindow with style WS_VISIBLE?
The way we hack around the asynchronous events is by checking for expose events in UpdateWindow, but of course if the app doesn't even use that it won't help. And on a slow connection the expose events will always arrive too late anyway. We'd need to explicitly wait for the event, but that would hurt badly on slow connections.
The app is processing in a WM_LBUTTONDOWN, and just creates a window and draws to it immediately, and the windows message loop wont redraw it. Is there any workaround for this or is it going to be an impossibility to get it working? (I wondered, for example, if we can do anything about ignoring the first expose if the window was created as visible, or removing the rdw_erase if the window had explicitly painted itself before the first event)?
Jason
"Ann & Jason Edmeades" us@edmeades.me.uk writes:
The difficulty here is the inability to directly query the concealed (within the struct DCE) clip_rgn not the visible region. For example, GetClipRgn returns dc->hClipRgn, whereas the dce clip_rgn is internal to user32 painting.c. The only call I can see replaces the region with GetDCEx?
What kind of test did you have in mind - The only idea I had was something like CreateWindow at 100,100, begin paint, MoveWindow to 50,50, FillRect into red, endpaint, then read it back to see if it really is read?
No, nothing like that. You could create say a 100x100 window, a 50x50 region, do GetDCEx with that clip region, then move/resize the window and check how the DC visible region changes. Then the same thing with InvalidateRgn+BeginPaint instead of GetDCEx.
The app is processing in a WM_LBUTTONDOWN, and just creates a window and draws to it immediately, and the windows message loop wont redraw it. Is there any workaround for this or is it going to be an impossibility to get it working? (I wondered, for example, if we can do anything about ignoring the first expose if the window was created as visible, or removing the rdw_erase if the window had explicitly painted itself before the first event)?
We can't know if the app has painted itself, it's quite possible that the window wasn't mapped yet when it painted, since this can be intercepted by the window manager. We'd have to buffer the output in a pixmap before the first expose event.