View Issue Details

IDProjectCategoryView StatusLast Update
0032141LazarusWidgetsetpublic2020-04-03 10:59
ReporterValdas Jankūnas Assigned ToZeljan Rikalo  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Platformlinux 4.10.0-26-genericOSKubuntu 17.04 
Product Version1.9 (SVN) 
Summary0032141: BitBlt copies from ghost canvas when it is applied to same canvas
DescriptionRun attached test project. There on OnPaint event of TPaintBox:
 - right side of canvas is filled with white color (using FillRect),
 - left side of canvas is filled (using BitBlt) with copies of left column from previously filled area,
 - in last step in right side of canvas (which is filled with FillRect) a horizontal line is drawn.

In Gtk2 as expected (see attached pic): line only in right side.
In Qt is mess (see attached pics):
 - immediately after start right side of canvas filled with pixels from my desktop background,
 - after refresh line runs across entire canvas.

Seems that in Qt WS BitBlt takes data from some buffer of Canvas :/
Additional InformationFPC v 3.0.0
KDE uses Qt v 5.7.1

Not sure what Qt version test application uses. How to get that info?
TagsNo tags attached.
Fixed in Revision62870
LazTarget-
WidgetsetQT, QT5
Attached Files

Activities

Valdas Jankūnas

2017-07-12 21:47

reporter  

test_project.zip (66,492 bytes)

Valdas Jankūnas

2017-07-12 21:47

reporter  

result_gtk2.png (7,817 bytes)   
result_gtk2.png (7,817 bytes)   

Valdas Jankūnas

2017-07-12 21:48

reporter  

result_qt__after_start.png (8,454 bytes)   
result_qt__after_start.png (8,454 bytes)   

Valdas Jankūnas

2017-07-12 21:48

reporter  

result_qt__after_refresh.png (7,830 bytes)   
result_qt__after_refresh.png (7,830 bytes)   

Valdas Jankūnas

2017-07-13 13:53

reporter   ~0101691

In Windows 7 (running in VirtualBox) it looks OK (see attached picture).

Valdas Jankūnas

2017-07-13 15:24

reporter   ~0101692

I tried to copy with BitBlt not filled area but previously drawn image. Attached test project "test_project__using_Image.zip".
 In Windows 7 (running in VirtualBox; Lazarus 1.9.0; FPC 3.0.0) it behaves strange (picture "result__image__win.png").
 In Qt (linux) at start PaintBox shows black boxes (picture "result__image__qt__after start.png") and after refresh (bring mouse pointer over PaintBox) it shows correct result (picture "result__image__qt__after_refresh.png").
 In Gtk2 it works without problems (picture "result__image__gtk2.png").

Valdas Jankūnas

2017-07-13 15:24

reporter  

Valdas Jankūnas

2017-07-13 15:24

reporter  

result__image__win.png (6,142 bytes)   
result__image__win.png (6,142 bytes)   

Valdas Jankūnas

2017-07-13 15:25

reporter  

Valdas Jankūnas

2017-07-13 15:25

reporter  

Valdas Jankūnas

2017-07-13 15:25

reporter  

result__image__gtk2.png (11,145 bytes)   
result__image__gtk2.png (11,145 bytes)   

Valdas Jankūnas

2017-07-15 12:41

reporter   ~0101719

Last edited: 2017-07-15 14:38

View 3 revisions

Seems that there is a lag in *Blt operation. It can be seen by modifying test project (with "BitBlt") with this code:

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
    if (Tag = 0) then
        Tag := 1
    else
        Tag := 0;

    if (Tag = 0) then
        PaintBox1.Canvas.Brush.Color := clYellow
    else
        PaintBox1.Canvas.Brush.Color := clRed;
    PaintBox1.Canvas.FillRect(0, 0, Image1.Width, Image1.Height);

    BitBlt(PaintBox1.Canvas.Handle,
           Image1.Width, 0, Image1.Width, Image1.Height,
           PaintBox1.Canvas.Handle,
           0, 0,
           SRCCOPY);
end;

 I tested it in Qt WS: every time I move mouse pointer over PaintBox1 it refreshes itself, and every time it contains boxes with different colors.

 In Win32 WS (Windows 7 in VirtualBox) it produces weird result: after start all boxes are red, but if I move window off screen (bottom) and then bring it back to induce Repaint of PaintBox1 then I get result showed in attached picture "weird_result_win32.png".
 
 I also ran this project in real laptop with Windows XP and performed previously mentioned "of screen" trick. Result in attached picture "result_real_winxp.png". Notice red-yellow band, I don't know what is going there. Maybe I blindly making obvious mistake?

 When instead of PaintBox1.Canvas a TImage.Picture.Bitmap.Canvas is used then project (with BitBlt and image) outputs correct results in Qt, Gtk2 and Win32 WS. Problems with PaintBox.OnPaint event?

Valdas Jankūnas

2017-07-15 12:41

reporter  

weird_result_win32.png (5,810 bytes)   
weird_result_win32.png (5,810 bytes)   

Valdas Jankūnas

2017-07-15 12:59

reporter  

result_real_winxp.png (3,292 bytes)   
result_real_winxp.png (3,292 bytes)   

Valdas Jankūnas

2017-07-16 15:56

reporter   ~0101727

With Qt5 WS (Qt5 v.5.7.1) first project (file "test_project.zip") crashes with output in to console:
QWidget::repaint: Recursive repaint detected
QWidget::repaint: Recursive repaint detected
this function is deprecated, use QScreen::grabWindow() instead. Defaulting to primary screen.
this function is deprecated, use QScreen::grabWindow() instead. Defaulting to primary screen.

... more than 20 same lines ...

this function is deprecated, use QScreen::grabWindow() instead. Defaulting to primary screen.
this function is deprecated, use QScreen::grabWindow() instead. Defaulting to primary screen.
QPainter::end: Painter ended with 2 saved states
TApplication.HandleException Access violation
  Stack trace:
  $00007EFE13371D60

Zeljan Rikalo

2017-07-21 13:25

developer   ~0101836

Qt5 assertion fixed in r55555

Zeljan Rikalo

2017-08-22 18:08

developer  

qtbitblt_samedevice.diff (2,641 bytes)   
Index: lcl/interfaces/qt/qtwidgets.pas
===================================================================
--- lcl/interfaces/qt/qtwidgets.pas	(revision 55733)
+++ lcl/interfaces/qt/qtwidgets.pas	(working copy)
@@ -4165,7 +4165,7 @@
   Color: TQColor;
   R: TRect;
 begin
-  if CanSendLCLMessage and (LCLObject is TWinControl) then
+  if CanSendLCLMessage and (LCLObject is TWinControl) and (FContext = 0) then
   begin
     if LCLObject.Color = clDefault then
       Color := Palette.DefaultColor
@@ -4201,7 +4201,7 @@
   {$ifdef VerboseQt}
     WriteLn('TQtWidget.SlotPaint ', dbgsName(LCLObject));
   {$endif}
-  if CanSendLCLMessage and (LCLObject is TWinControl) then
+  if CanSendLCLMessage and (LCLObject is TWinControl) and (FContext = 0) then
   begin
     FillChar(Msg{%H-}, SizeOf(Msg), #0);
 
Index: lcl/interfaces/qt/qtwinapi.inc
===================================================================
--- lcl/interfaces/qt/qtwinapi.inc	(revision 55733)
+++ lcl/interfaces/qt/qtwinapi.inc	(working copy)
@@ -6793,6 +6793,8 @@
   OldBkColor: TColorRef;
   RestoreClip: Boolean;
   AClipRect: TRect;
+  APoint: TQtPoint;
+  ARegion: QRegionH;
 begin
   {$ifdef VerboseQtWinAPI}
     WriteLn('[WinAPI StretchMaskBlt]',
@@ -6812,12 +6814,30 @@
   begin
     if SrcQDC.Parent <> nil then
     begin
-      with SrcQDC.getDeviceSize do
-        TmpPixmap := QPixmap_create(x, y);
-      QPixmap_grabWindow(TmpPixmap, QWidget_winId(SrcQDC.Parent), 0, 0);
-      Image := QImage_create();
-      QPixmap_toImage(TmpPixmap, Image);
-      QPixmap_destroy(TmpPixmap);
+      if DestDC = SrcDC then
+      begin
+        // we are same DC issue #32141
+        with SrcQDC.getDeviceSize do
+          TmpPixmap := QPixmap_create(x, y);
+        // TmpPixmap := QPixmap_create(QWidget_width(SrcQDC.Parent), QWidget_height(SrcQDC.Parent));
+        QPixmap_fill(TmpPixmap, SrcQDC.brush.getColor);
+        APoint.X := 0;
+        APoint.Y := 0;
+        ARegion := QRegion_create(0, 0, QPixmap_width(TmpPixmap), QPixmap_height(TmpPixmap));
+        QWidget_render(SrcQDC.Parent, QPaintDeviceH(TmpPixmap), @APoint, ARegion, QWidgetDrawChildren);
+        QRegion_destroy(ARegion);
+        Image := QImage_create();
+        QPixmap_toImage(TmpPixmap, Image);
+        QPixmap_destroy(TmpPixmap);
+      end else
+      begin
+        with SrcQDC.getDeviceSize do
+          TmpPixmap := QPixmap_create(x, y);
+        QPixmap_grabWindow(TmpPixmap, QWidget_winId(SrcQDC.Parent), 0, 0);
+        Image := QImage_create();
+        QPixmap_toImage(TmpPixmap, Image);
+        QPixmap_destroy(TmpPixmap);
+      end;
     end
     else
       Exit;
qtbitblt_samedevice.diff (2,641 bytes)   

Zeljan Rikalo

2017-08-22 18:09

developer   ~0102311

There's problem with QPixmap_grabWindow(). I've got nice result with QWidget_render() instead of QPixmap_grabWindow() inside TQtWidgetSet.StretchMaskBlt(), but must fix infinite paintEvent loop to get this work (simple check if FContext = 0 inside SlotPaintBg and SlotPaint isn't good enough). Please test with attached patch (even more tests are needed than this simple example to be sure that I'm correct about my observations).

Zeljan Rikalo

2017-08-23 11:03

developer   ~0102330

Forget about my patch, it does not work correct with second example (image).

jamie philbrook

2017-08-24 00:07

reporter   ~0102338

For such an effect like that I usually put in a blocking Boolean variable.

Inside this code block.--
procedure TForm1.PaintBox1Paint(Sender: TObject);
Const
  Busy : Boolean = False;

Begin
  If Busy Then Exit else Busy := True;
  
   DO the code now;

 Busy := False;
End;

Zeljan Rikalo

2020-04-03 10:59

developer   ~0121859

Qt/Qt5 is fixed. Note that first example with blackline cannot be fixed at all under qt/qt5, even QWidget_render() does not help

Issue History

Date Modified Username Field Change
2017-07-12 21:47 Valdas Jankūnas New Issue
2017-07-12 21:47 Valdas Jankūnas File Added: test_project.zip
2017-07-12 21:47 Valdas Jankūnas File Added: result_gtk2.png
2017-07-12 21:48 Valdas Jankūnas File Added: result_qt__after_start.png
2017-07-12 21:48 Valdas Jankūnas File Added: result_qt__after_refresh.png
2017-07-13 13:53 Valdas Jankūnas Note Added: 0101691
2017-07-13 15:24 Valdas Jankūnas Note Added: 0101692
2017-07-13 15:24 Valdas Jankūnas File Added: test_project__using_Image.zip
2017-07-13 15:24 Valdas Jankūnas File Added: result__image__win.png
2017-07-13 15:25 Valdas Jankūnas File Added: result__image__qt__after start.png
2017-07-13 15:25 Valdas Jankūnas File Added: result__image__qt__after_refresh.png
2017-07-13 15:25 Valdas Jankūnas File Added: result__image__gtk2.png
2017-07-13 17:35 Zeljan Rikalo Assigned To => Zeljan Rikalo
2017-07-13 17:35 Zeljan Rikalo Status new => assigned
2017-07-15 12:41 Valdas Jankūnas Note Added: 0101719
2017-07-15 12:41 Valdas Jankūnas File Added: weird_result_win32.png
2017-07-15 12:58 Valdas Jankūnas Note Edited: 0101719 View Revisions
2017-07-15 12:59 Valdas Jankūnas File Added: result_real_winxp.png
2017-07-15 14:38 Valdas Jankūnas Note Edited: 0101719 View Revisions
2017-07-16 15:56 Valdas Jankūnas Note Added: 0101727
2017-07-21 13:25 Zeljan Rikalo Note Added: 0101836
2017-08-22 18:08 Zeljan Rikalo File Added: qtbitblt_samedevice.diff
2017-08-22 18:09 Zeljan Rikalo LazTarget => -
2017-08-22 18:09 Zeljan Rikalo Note Added: 0102311
2017-08-22 18:09 Zeljan Rikalo Status assigned => confirmed
2017-08-23 11:03 Zeljan Rikalo Note Added: 0102330
2017-08-24 00:07 jamie philbrook Note Added: 0102338
2020-04-03 10:59 Zeljan Rikalo Status confirmed => resolved
2020-04-03 10:59 Zeljan Rikalo Resolution open => fixed
2020-04-03 10:59 Zeljan Rikalo Fixed in Revision => 62870
2020-04-03 10:59 Zeljan Rikalo Widgetset QT, QT5 => QT, QT5
2020-04-03 10:59 Zeljan Rikalo Note Added: 0121859