Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2011-05

Getting update rect/region in Windows

15 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Max Vlasov

Hi,
I encountered a problem I don't know how to solve.

Some background. Any OS does a great job avoiding unnecessary drawing even if the program tries to draw everything in the window. But there are exceptions.
- There are some functions, for example region-related in windows that nevertheless process full job even if the area the developer is drawing is not included in the window update region
- There are internal off-screen manipulation so the developer himself have to do the job of avoiding extra processing so needs to know what the update region is .

In Delphi I used the following trick. In the WM_Paint before inheried call I got update region with successive calls to GetUpdateRect (to determine if it exists) and GetUpdateRgn afterwards. This allowed to get the correct region before BeginPaint is called (it validates the region so getting it after BeginPaint makes no sense).

But in Lazarus WM_Paint handler already contains DC and also GetUpdateRect call is failed. As I understand, this is because the WindowProc from win32callback.inc already did BeginPaint and provided the dc for the following call to the control WM_Paint.

So the questions are:
- is there a chance to intervene into lazarus drawing chain to get the update region before lazarus root windowproc call.
- if the first is not possible (or too complex) is it possible for lazarus to save the update region somewhere before BeginPaint or maybe do this optionally based on the special property value sure set to false by default

Thanks

Max Vlasov
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110522/c31a13cd/attachment.html>

Reply by email

Zaher Dirkey
to Max Vlasov

2011/5/22 Max Vlasov

Show quoted text 36 lines
Hi, I encountered a problem I don't know how to solve. Some background. Any OS does a great job avoiding unnecessary drawing even if the program tries to draw everything in the window. But there are exceptions. - There are some functions, for example region-related in windows that nevertheless process full job even if the area the developer is drawing is not included in the window update region - There are internal off-screen manipulation so the developer himself have to do the job of avoiding extra processing so needs to know what the update region is . In Delphi I used the following trick. In the WM_Paint before inheried call I got update region with successive calls to GetUpdateRect (to determine if it exists) and GetUpdateRgn afterwards. This allowed to get the correct region before BeginPaint is called (it validates the region so getting it after BeginPaint makes no sense). But in Lazarus WM_Paint handler already contains DC and also GetUpdateRect call is failed. As I understand, this is because the WindowProc from win32callback.inc already did BeginPaint and provided the dc for the following call to the control WM_Paint. So the questions are: - is there a chance to intervene into lazarus drawing chain to get the update region before lazarus root windowproc call. - if the first is not possible (or too complex) is it possible for lazarus to save the update region somewhere before BeginPaint or maybe do this optionally based on the special property value sure set to false by default Thanks Max Vlasov

Check Canvas.ClipRect

Zaher Dirkey
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110522/4452faf9/attachment.html>

Reply by email

Max Vlasov
to Zaher Dirkey

2011/5/22 Zaher Dirkey

Show quoted text 25 lines
2011/5/22 Max Vlasov > Hi, > I encountered a problem I don't know how to solve. > > In Delphi I used the following trick. In the WM_Paint before inheried call > I got update region with successive calls to GetUpdateRect (to determine if > it exists) and GetUpdateRgn afterwards. This allowed to get the correct > region before BeginPaint is called (it validates the region so getting it > after BeginPaint makes no sense). > > But in Lazarus WM_Paint handler already contains DC and also GetUpdateRect > call is failed. As I understand, this is because the WindowProc from > win32callback.inc already did BeginPaint and provided the dc for the > following call to the control WM_Paint. > > > Max Vlasov > > Check Canvas.ClipRect

Zaher, thanks,
but this is irrelevant, clipping rects and regions is just the way to define canvas/device context limiting area until explicitly canceled. It was used by Delphi and (probably) Lazarus to implement TGraphicControl, component working almost as TWinControl but without window handles.

The update region is the region formed by multiply InvalidateRect and InvalidateRgn calls and it exists until BeginPaint is called as a result of Wm_paint message. Invalidation is more correct way to redraw anything on the window (vs direct drawing when necessary)

Max

Max
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110522/b02b78d1/attachment.html>

Reply by email

Zaher Dirkey
to Max Vlasov

2011/5/22 Max Vlasov

Show quoted text 44 lines
2011/5/22 Zaher Dirkey > > 2011/5/22 Max Vlasov > >> Hi, >> I encountered a problem I don't know how to solve. >> >> In Delphi I used the following trick. In the WM_Paint before inheried >> call I got update region with successive calls to GetUpdateRect (to >> determine if it exists) and GetUpdateRgn afterwards. This allowed to get the >> correct region before BeginPaint is called (it validates the region so >> getting it after BeginPaint makes no sense). >> >> But in Lazarus WM_Paint handler already contains DC and also >> GetUpdateRect call is failed. As I understand, this is because the >> WindowProc from win32callback.inc already did BeginPaint and provided the dc >> for the following call to the control WM_Paint. >> >> >> Max Vlasov >> >> > Check Canvas.ClipRect > > > Zaher, thanks, but this is irrelevant, clipping rects and regions is just the way to define canvas/device context limiting area until explicitly canceled. It was used by Delphi and (probably) Lazarus to implement TGraphicControl, component working almost as TWinControl but without window handles. The update region is the region formed by multiply InvalidateRect and InvalidateRgn calls and it exists until BeginPaint is called as a result of Wm_paint message. Invalidation is more correct way to redraw anything on the window (vs direct drawing when necessary) Max

Not understand u, can u give us an example
Thanks

Zaher Dirkey -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110522/0b08962b/attachment.html>

Reply by email

Max Vlasov
to Zaher Dirkey

2011/5/22 Zaher Dirkey

Show quoted text 45 lines
2011/5/22 Max Vlasov > > > 2011/5/22 Zaher Dirkey > >> >> 2011/5/22 Max Vlasov >> >>> Hi, >>> I encountered a problem I don't know how to solve. >>> >>> In Delphi I used the following trick. In the WM_Paint before inheried >>> call I got update region with successive calls to GetUpdateRect (to >>> determine if it exists) and GetUpdateRgn afterwards. This allowed to get the >>> correct region before BeginPaint is called (it validates the region so >>> getting it after BeginPaint makes no sense). >>> >>> But in Lazarus WM_Paint handler already contains DC and also >>> GetUpdateRect call is failed. As I understand, this is because the >>> WindowProc from win32callback.inc already did BeginPaint and provided the dc >>> for the following call to the control WM_Paint. >>> >>> >>> Max Vlasov >>> >>> >> Check Canvas.ClipRect >> >> >> > > Zaher, thanks, > but this is irrelevant, clipping rects and regions is just the way to > define canvas/device context limiting area until explicitly canceled. It was > used by Delphi and (probably) Lazarus to implement TGraphicControl, > component working almost as TWinControl but without window handles. > ... > Max > > Not understand u, can u give us an example Thanks --

Ok,
simple form, one button. The following code works in Delphi (press button, redrawing with Alt-Tab or by dragging some other window over this window). In Lazarus it always goes to 'failed'.
My version: with Delphi vcl logic BeginPaint will be inside inherited, with Lazarus it already was before in the non-object WindowProc

Max
...

procedure TForm1.Button1Click(Sender: TObject);
begin
  { change Bounds to @ARect in Delphi since it's declared as PRect }
  InvalidateRect(Handle, Bounds(0, 0, 100, 100), true);
end;
...
  private
    procedure  WmPaint(var Msg: TWmPaint);message WM_Paint;
procedure TForm1.WmPaint(var Msg: TWmPaint);
var
  ARect: TRect;
begin
  if GetUpdateRect(Handle, ARect, false) then
  begin
    Caption:=format('Update Rect is ok (%d, %d, %d, %d)', [ARect.Left,
ARect.Top, ARect.Right, ARect.Bottom]);
  end
  else
    Caption:='Update Rect is failed';
  inherited;

end;
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110522/436b31aa/attachment-0001.html>

Reply by email

Max Vlasov
to Hans-Peter Diettrich: I use to restrict expensive painting to the ClipRect. The entire painting has to be…
Hans-Peter Diettrich wrote 19 lines
Max Vlasov schrieb: - There are some functions, for example region-related in windows that > nevertheless process full job even if the area the developer is drawing is > not included in the window update region > - There are internal off-screen manipulation so the developer himself have > to do the job of avoiding extra processing so needs to know what the update > region is . > I use to restrict expensive painting to the ClipRect. The entire painting has to be organized into kind of "objects", which reside in distinct parts of the entire canvas - just like controls reside in distinct parts of the client area. Before retrieving the entire painting information, I get the object's rectangle and check whether it intersects with the ClipRect. If not, painting is skipped for that object.

Ok, another example. Imagine that two alpha png is merged and drawed on the form on the fly. And you drag a small window over this form. My experience tells me that win32 will do great automatic job of narrowing the final drawing of the bitmap to smallest rectangle possible, but my internal procedures of alpha-blending can get this information only from GetUpdateRect/GetUpdateRgn, otherwise every single pixel moving of this window will lead to full alpha-blending of these bitmaps. ClipRect won't provide this information

Max
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110522/b61e3a44/attachment.html>

Reply by email

Hans-Peter Diettrich
to Max Vlasov: I encountered a problem I don't know how to solve. Some background. Any OS does a great…
Show quoted text 6 lines
- There are some functions, for example region-related in windows that nevertheless process full job even if the area the developer is drawing is not included in the window update region - There are internal off-screen manipulation so the developer himself have to do the job of avoiding extra processing so needs to know what the update region is .

I use to restrict expensive painting to the ClipRect. The entire painting has to be organized into kind of "objects", which reside in distinct parts of the entire canvas - just like controls reside in distinct parts of the client area. Before retrieving the entire painting information, I get the object's rectangle and check whether it intersects with the ClipRect. If not, painting is skipped for that object.

DoDi

Reply by email

Zaher Dirkey
to Max Vlasov: 2011/5/22 Zaher Dirkey simple form, one button. The following code works in Delphi (press…

2011/5/22 Max Vlasov

Show quoted text 88 lines
2011/5/22 Zaher Dirkey > 2011/5/22 Max Vlasov > >> >> >> 2011/5/22 Zaher Dirkey >> >>> >>> 2011/5/22 Max Vlasov >>> >>>> Hi, >>>> I encountered a problem I don't know how to solve. >>>> >>>> In Delphi I used the following trick. In the WM_Paint before inheried >>>> call I got update region with successive calls to GetUpdateRect (to >>>> determine if it exists) and GetUpdateRgn afterwards. This allowed to get the >>>> correct region before BeginPaint is called (it validates the region so >>>> getting it after BeginPaint makes no sense). >>>> >>>> But in Lazarus WM_Paint handler already contains DC and also >>>> GetUpdateRect call is failed. As I understand, this is because the >>>> WindowProc from win32callback.inc already did BeginPaint and provided the dc >>>> for the following call to the control WM_Paint. >>>> >>>> >>>> Max Vlasov >>>> >>>> >>> Check Canvas.ClipRect >>> >>> >>> >> >> Zaher, thanks, >> but this is irrelevant, clipping rects and regions is just the way to >> define canvas/device context limiting area until explicitly canceled. It was >> used by Delphi and (probably) Lazarus to implement TGraphicControl, >> component working almost as TWinControl but without window handles. >> ... >> Max >> >> > Not understand u, can u give us an example > Thanks > -- > Ok, simple form, one button. The following code works in Delphi (press button, redrawing with Alt-Tab or by dragging some other window over this window). In Lazarus it always goes to 'failed'. My version: with Delphi vcl logic BeginPaint will be inside inherited, with Lazarus it already was before in the non-object WindowProc Max ... procedure TForm1.Button1Click(Sender: TObject); begin { change Bounds to @ARect in Delphi since it's declared as PRect } InvalidateRect(Handle, Bounds(0, 0, 100, 100), true); end; ... private procedure WmPaint(var Msg: TWmPaint);message WM_Paint; procedure TForm1.WmPaint(var Msg: TWmPaint); var ARect: TRect; begin if GetUpdateRect(Handle, ARect, false) then begin Caption:=format('Update Rect is ok (%d, %d, %d, %d)', [ARect.Left, ARect.Top, ARect.Right, ARect.Bottom]); end else Caption:='Update Rect is failed'; inherited; end;
In Lazarus i used
procedure Paint; override;

and

Canvas.ClipRect;

It is work for me as Hans-Peter said in his message.

If you ask about Rgn (Region), it more complected to work on all platforms, i think it is not founded.

Zaher Dirkey -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110522/cc4ef128/attachment.html>

Reply by email

Max Vlasov
to Zaher Dirkey

2011/5/22 Zaher Dirkey

Show quoted text 76 lines
2011/5/22 Max Vlasov > > > 2011/5/22 Zaher Dirkey > >> 2011/5/22 Max Vlasov >> >>> >>> >>> 2011/5/22 Zaher Dirkey >>> >>>> >>>> 2011/5/22 Max Vlasov >>>> >>>>> Hi, >>>>> I encountered a problem I don't know how to solve. >>>>> >>>>> In Delphi I used the following trick. In the WM_Paint before inheried >>>>> call I got update region with successive calls to GetUpdateRect (to >>>>> determine if it exists) and GetUpdateRgn afterwards. This allowed to get the >>>>> correct region before BeginPaint is called (it validates the region so >>>>> getting it after BeginPaint makes no sense). >>>>> >>>>> But in Lazarus WM_Paint handler already contains DC and also >>>>> GetUpdateRect call is failed. As I understand, this is because the >>>>> WindowProc from win32callback.inc already did BeginPaint and provided the dc >>>>> for the following call to the control WM_Paint. >>>>> >>>>> >>>>> Max Vlasov >>>>> >>>>> >>>> Check Canvas.ClipRect >>>> >>>> >>>> >>> >>> Zaher, thanks, >>> but this is irrelevant, clipping rects and regions is just the way to >>> define canvas/device context limiting area until explicitly canceled. It was >>> used by Delphi and (probably) Lazarus to implement TGraphicControl, >>> component working almost as TWinControl but without window handles. >>> ... >>> Max >>> >>> >> Not understand u, can u give us an example >> Thanks >> -- >> > > > Ok, > simple form, one button. The following code works in Delphi (press button, > redrawing with Alt-Tab or by dragging some other window over this window). > In Lazarus it always goes to 'failed'. > My version: with Delphi vcl logic BeginPaint will be inside inherited, > with Lazarus it already was before in the non-object WindowProc > > Max > > In Lazarus i used procedure Paint; override; and Canvas.ClipRect; It is work for me as Hans-Peter said in his message. If you ask about Rgn (Region), it more complected to work on all platforms, i think it is not founded.

Thanks, I understand that I should avoid any platform-specific code if I want inter-platform compatibility.

Currently I tried to intervene calling SetWindowLong(... GWL_WNDPROC) and inside my "overriden" Window Proc I get the region and call WindowProc and it helped. If anyone knows more "official" way to do this, please let me know.

Max
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110522/b83f72b0/attachment-0001.html>

Reply by email

Hans-Peter Diettrich
to Max Vlasov: On Sun, May 22, 2011 at 6:49 PM, Hans-Peter Diettrich Ok, another example. Imagine that…
Ok, another example. Imagine that two alpha png is merged and drawed on the form on the fly.

Is that on-the-fly merging really necessary?

Show quoted text 7 lines
And you drag a small window over this form. My experience tells me that win32 will do great automatic job of narrowing the final drawing of the bitmap to smallest rectangle possible, but my internal procedures of alpha-blending can get this information only from GetUpdateRect/GetUpdateRgn, otherwise every single pixel moving of this window will lead to full alpha-blending of these bitmaps. ClipRect won't provide this information

I'm not sure what you mean. When the dragged window also uses alpha-blending, then Windows (GDI) must do that job. Using GetUpdateRect IMO should not work, because BeginPaint restricts output to the ClipRect.

DoDi

Reply by email

Max Vlasov
to Hans-Peter Diettrich: Is that on-the-fly merging really necessary? I'm not sure what you mean. When the dragged…

On Mon, May 23, 2011 at 12:43 AM, Hans-Peter Diettrich <

Show quoted text 29 lines
wrote: Max Vlasov schrieb: Ok, another example. Imagine that two alpha png is merged and drawed on > the form on the fly. > Is that on-the-fly merging really necessary? And you drag a small window over this form. My experience tells me that > win32 will do great automatic job of narrowing the final drawing of the > bitmap to smallest rectangle possible, but my internal procedures of > alpha-blending can get this information only from > GetUpdateRect/GetUpdateRgn, otherwise every single pixel moving of this > window will lead to full alpha-blending of these bitmaps. ClipRect won't > provide this information > I'm not sure what you mean. When the dragged window also uses alpha-blending, then Windows (GDI) must do that job. Using GetUpdateRect IMO should not work, because BeginPaint restricts output to the ClipRect. DoDi

I must admit I was wrong saying that ClipRect doesn't provide the information about updating areas. It does, partly my misunderstanding came from the naming change in Delphi. Usually win32 rect/region api functions comes in pairs with similar names, but ClipRect property is not a call to GetClipRect (there's no such function), but to GetClipBox function that is just partly related to clipping regions. And Luiz is also right referring to rcPaint member. So if one needs the update rect, there are plenty of options already.

Actually I needed access not only to update rect, but to the update region (for example in order to effectively resolve small rectangles in different areas of a big window). In this case I also found a replacement for GetUpdateRgn, it's GetRandomRgn, documented not so long ago (so I was not aware of its existence) and according to the help it contains the correct region not only before, but also after BeginPaint. So I will probably use this one instead of windowproc hacking

As for necessity for on-the-fly drawing, I usually pay much attention to resources used and don't allocate much unless is necessary. The system working on the fly consumes much less memory because doesn't use intermediate buffer. Sometimes it even can not use bitmaps at all (regions filling/framing) So there are several approaches, I think they all have their rights to exist.

Max
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110523/963b289a/attachment.html>

Reply by email

Hans-Peter Diettrich
to Max Vlasov
Show quoted text 8 lines
I must admit I was wrong saying that ClipRect doesn't provide the information about updating areas. It does, partly my misunderstanding came from the naming change in Delphi. Usually win32 rect/region api functions comes in pairs with similar names, but ClipRect property is not a call to GetClipRect (there's no such function), but to GetClipBox function that is just partly related to clipping regions. And Luiz is also right referring to rcPaint member. So if one needs the update rect, there are plenty of options already.

I've learned about Windows painting with Win 3.0, so my memory also may be a bit outdated now.

Show quoted text 7 lines
Actually I needed access not only to update rect, but to the update region (for example in order to effectively resolve small rectangles in different areas of a big window). In this case I also found a replacement for GetUpdateRgn, it's GetRandomRgn, documented not so long ago (so I was not aware of its existence) and according to the help it contains the correct region not only before, but also after BeginPaint. So I will probably use this one instead of windowproc hacking

IMO the entire update region should be available for every window (by HWND).

Show quoted text 6 lines
As for necessity for on-the-fly drawing, I usually pay much attention to resources used and don't allocate much unless is necessary. The system working on the fly consumes much less memory because doesn't use intermediate buffer. Sometimes it even can not use bitmaps at all (regions filling/framing) So there are several approaches, I think they all have their rights to exist.

I've stopped optimizing (display) memory usage many years ago. At least Windows only keeps the actually required code and data in RAM (pages), so that memory usage is of interest only in very small (embedded, portable...) systems. When Windows nowadays keeps copies of the form bitmaps (ghosting), I see no more reason for replacing double-buffer by complicated code and on-the-fly painting.

DoDi

Reply by email

Max Vlasov
to Hans-Peter Diettrich
Hans-Peter Diettrich wrote 12 lines
Actually I needed access not only to update rect, but to the update region (for example in order to effectively resolve small rectangles in different areas of a big window). In this case I also found a replacement for GetUpdateRgn, it's GetRandomRgn, documented not so long ago (so I was not aware of its existence) and according to the help it contains the correct region not only before, but also after BeginPaint. So I will probably use this one instead of windowproc hacking IMO the entire update region should be available for every window (by HWND).

As I suppose regions are implemented differently on other platforms (Linux/MacOS), right? Thanks to this discussion I made a progress with a software that I wanted to be compatible with Lazarus ( http://www.maxerist.net/main/soft-for-win/tubicus) . It's a tetris-inspired game and is gnu gpl. I would like to made it compatible with other platforms, but I'm not sure whether I should change region-based logic to something else in this case. I will be glad to hear any advice on this.

Max
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus.freepascal.org/pipermail/lazarus/attachments/20110524/4a04b83b/attachment.html>

Reply by email

Hans-Peter Diettrich
to Max Vlasov
tetris-inspired game and is gnu gpl. I would like to made it compatible with other platforms, but I'm not sure whether I should change region-based logic to something else in this case. I will be glad to hear any advice on this.

I don't know about concrete window managers, except for Windows, but IMO there is little room for very different algorithms. A window (screen) manager has to track modifications to a window (requiring repaint), and has to take into account possibly overlapping windows, and widgets inside the client area. In the simplest implementation all update and clip regions are implemented as lists of rectangles. The only choice is the implementation of clipping, which can be done by painting all update rectangles in explicit (sequential) painting requests, or otherwise leave clipping to the graphics library. In either case the paint handlers have to deal with a single rectangular area (ClipRect), IMO.

DoDi

Reply by email