View Issue Details

IDProjectCategoryView StatusLast Update
0031780LazarusWidgetsetpublic2017-05-23 13:54
ReporterAnton Kavalenka Assigned ToZeljan Rikalo  
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
Platformi386OSLinux 
Product Version1.9 (SVN) 
Summary0031780: gtk3: TGraphicControl canvas wrong offset
DescriptionTGraphicControl obtains cairo surface (Canvas handle) from the parent widget. Seems like it is being offset by unknown value in Y direction before painting.
Generic painting on TForm canvas draws proper diagonal green line.

Click inside the red frame (it is the BoundsRect of the Label1)

Patch (gtk3obj.diff) should be applied before the test.
Steps To ReproduceApply the patch that makes default pent mode pmCopy (it seems it should be that), otherwise the pen color would not be changed. Also rectangle should not be filled (FillRect is intended for).
Additional InformationSeems like this canvas offset problem prevent TTreeView proper display in GTK3. Each node is drawn at offset remained from previous painting.
TagsNo tags attached.
Fixed in Revision55060
LazTarget-
WidgetsetGTK 3
Attached Files

Activities

Anton Kavalenka

2017-05-08 17:33

reporter  

laztest103.zip (129,379 bytes)

Anton Kavalenka

2017-05-08 17:33

reporter  

gtk3obj.diff (984 bytes)   
Index: gtk3objects.pas
===================================================================
--- gtk3objects.pas	(revision 54833)
+++ gtk3objects.pas	(working copy)
@@ -802,6 +802,7 @@
   FStyle := psSolid;
   FEndCap := pecFlat;
   FJoinStyle := pjsRound;
+  FPenMode := pmCopy; // default pen mode
 end;
 
 procedure TGtk3Pen.setCosmetic(b: Boolean);
@@ -990,7 +991,6 @@
   w: Double;
 begin
   SetSourceColor(FCurrentPen.Color);
-
   case FCurrentPen.Mode of
     pmBlack: begin
       SetSourceColor(clBlack);
Index: gtk3winapi.inc
===================================================================
--- gtk3winapi.inc	(revision 54833)
+++ gtk3winapi.inc	(working copy)
@@ -3221,7 +3221,7 @@
   R := NormalizeRect(Rect(X1, Y1, X2, Y2));
   if IsRectEmpty(R) then Exit(True);
   with R do
-    TGtk3DeviceContext(DC).drawRect(Left, Top, Right - Left, Bottom - Top, True);
+    TGtk3DeviceContext(DC).drawRect(Left, Top, Right - Left, Bottom - Top, false);
   Result := True;
 end;
 
gtk3obj.diff (984 bytes)   

Anton Kavalenka

2017-05-08 17:42

reporter  

Anton Kavalenka

2017-05-08 17:44

reporter   ~0100159

It seems like canvas is offset by window title size = 38 pix

Zeljan Rikalo

2017-05-08 21:04

developer   ~0100161

So does your patch fix offset or not ? I don't understand purpose of patch (except for FPenMode := pmCopy;)

Anton Kavalenka

2017-05-09 09:36

reporter   ~0100173

Purpose of patch to see the lines in color and get the rectangle hollow (not filled). Otherwise line color would be black, and rectangle filled with brush color. Proper offset should bring text into rectangle.

Patch does not fix the offset problem.
I did not found the place where obtained surface is being offset (none of the TGtk3DeviceContext methods like .Translate are called for this).

Zeljan Rikalo

2017-05-09 10:52

developer   ~0100174

TGtk3DeviceContext is in alpha state as complete gtk3.
You can add translation stuff...translation should be added in pain event of gtkwidget (gtk3widgets.pas)

Anton Kavalenka

2017-05-09 19:51

reporter   ~0100182

Last edited: 2017-05-09 19:51

View 2 revisions

Seems like windows with title and menu has already 1 transformation applied internally - shift by title+menu size in matrix.

The new transformation which have to be applied (move to new origin) should not include initial transformation.

Actual coordinate translation take place in Tgtk3WidgetSet.GetWindowOrgEx() / SetWindowOgEx. Excluding this non-client Y-shift in both functions resolves the problem.

Zeljan Rikalo

2017-05-09 20:17

developer   ~0100184

Feel free to create patch :)

Anton Kavalenka

2017-05-21 17:09

reporter  

gtk3up.diff (5,968 bytes)   
Index: gtk3objects.pas
===================================================================
--- gtk3objects.pas	(revision 55030)
+++ gtk3objects.pas	(working copy)
@@ -219,6 +219,7 @@
     Parent: PGtkWidget;
     Window: PGdkWindow;
     ParentPixmap: PGdkPixbuf;
+    fncOrigin:TPoint; // non-client area offsets surface origin
     constructor Create(AWidget: PGtkWidget; const APaintEvent: Boolean = False); virtual;
     constructor Create(AWindow: PGdkWindow; const APaintEvent: Boolean); virtual;
     constructor CreateFromCairo(AWidget: PGtkWidget; ACairo: PCairo_t); virtual;
@@ -802,6 +803,7 @@
   FStyle := psSolid;
   FEndCap := pecFlat;
   FJoinStyle := pjsRound;
+  FPenMode := pmCopy; // default pen mode
 end;
 
 procedure TGtk3Pen.setCosmetic(b: Boolean);
@@ -990,7 +992,6 @@
   w: Double;
 begin
   SetSourceColor(FCurrentPen.Color);
-
   case FCurrentPen.Mode of
     pmBlack: begin
       SetSourceColor(clBlack);
@@ -1208,6 +1209,8 @@
 end;
 
 procedure TGtk3DeviceContext.CreateObjects;
+var
+  Matrix:cairo_matrix_t;
 begin
   FBkMode := TRANSPARENT;
   FCurrentImage := nil;
@@ -1225,6 +1228,10 @@
   FCurrentFont := FFont;
   FvImage := TGtk3Image.Create(nil, 1, 1, 8, CAIRO_FORMAT_ARGB32);
   FCurrentImage := FvImage;
+
+  cairo_get_matrix(Widget, @Matrix);
+  // widget with menu or other non-client exclusions have offset in trasform matrix
+  fncOrigin:=Point(round(Matrix.x0),round(Matrix.y0));
 end;
 
 procedure TGtk3DeviceContext.DeleteObjects;
Index: gtk3winapi.inc
===================================================================
--- gtk3winapi.inc	(revision 55030)
+++ gtk3winapi.inc	(working copy)
@@ -2731,7 +2731,7 @@
 
 function TGtk3WidgetSet.GetWindowOrgEx(dc: hdc; P: PPoint): Integer;
 var
-  Matrix: Pcairo_matrix_t;
+  Matrix: cairo_matrix_t;
   dx: Double;
   dy: Double;
 begin
@@ -2746,22 +2746,17 @@
     {$endif}
     exit;
   end;
-  New(Matrix);
-  cairo_get_matrix(TGtk3DeviceContext(DC).Widget, Matrix);
-  if Matrix <> nil then
+  cairo_get_matrix(TGtk3DeviceContext(DC).Widget, @Matrix);
+  dx := 0;
+  dy := 0;
+  cairo_matrix_transform_point(@Matrix, @dx, @dy);
+  // DebugLn('GetWindowOrgEx POINT ',Format('dx %d dy %d',[-Trunc(Dx), -Trunc(Dy)]));
+  if P <> nil then
   begin
-    dx := 0;
-    dy := 0;
-    cairo_matrix_transform_point(Matrix, @dx, @dy);
-    // DebugLn('GetWindowOrgEx POINT ',Format('dx %d dy %d',[-Trunc(Dx), -Trunc(Dy)]));
-    if P <> nil then
-    begin
-      P^.X := -Trunc(DX);
-      P^.Y := -Trunc(DY);
-    end;
-    Result := 1;
-    Dispose(Matrix);
+    P^.X := -Trunc(DX)+TGtk3DeviceContext(DC).fncOrigin.X;
+    P^.Y := -Trunc(DY)+TGtk3DeviceContext(DC).fncOrigin.Y;
   end;
+  Result := 1;
 end;
 
 function TGtk3WidgetSet.GetWindowRect(Handle: hwnd; var ARect: TRect): Integer;
@@ -2907,7 +2902,7 @@
 
 function TGtk3WidgetSet.LPtoDP(DC: HDC; var Points; Count: Integer): BOOL;
 var
-  Matrix: Pcairo_matrix_t;
+  Matrix: cairo_matrix_t;
   cr: PCairo_t;
   P: PPoint;
   dx, dy: Double;
@@ -2921,26 +2916,23 @@
   if not IsValidDC(DC) then
     exit;
   cr := TGtk3DeviceContext(DC).Widget;
-  New(Matrix);
-  try
-    cairo_get_matrix(cr, Matrix);
-    P := @Points;
-    while Count > 0 do
-    begin
-      Dec(Count);
-      DX := P^.X;
-      DY := P^.Y;
-      // DebugLn('LPTODP INPUT ',Format('dx %2.2n dy %2.2n',[dx, dy]));
-      cairo_matrix_translate(Matrix, Dx, Dy);
-      cairo_matrix_transform_point(Matrix, @Dx, @Dy);
-      // DebugLn('LPTODP Output ',Format('dx %2.2n dy %2.2n',[dx, dy]));
-      P^.X := Round(DX);
-      P^.Y := Round(DY);
-      Inc(P);
-    end;
-  finally
-    Dispose(Matrix);
+
+  P := @Points;
+  while Count > 0 do
+  begin
+    Dec(Count);
+    DX := P^.X;
+    DY := P^.Y;
+    // DebugLn('LPTODP INPUT ',Format('dx %2.2n dy %2.2n',[dx, dy]));
+    //cairo_matrix_translate(@Matrix, Dx, Dy);
+    //cairo_matrix_transform_point(@Matrix, @Dx, @Dy);
+    cairo_user_to_device(cr,@dx,@dy);
+    // DebugLn('LPTODP Output ',Format('dx %2.2n dy %2.2n',[dx, dy]));
+    P^.X := Round(DX)-TGtk3DeviceContext(DC).fncOrigin.x;
+    P^.Y := Round(DY)-TGtk3DeviceContext(DC).fncOrigin.y;
+    Inc(P);
   end;
+  Result:=true;
 end;
 
 function MessageButtonClicked(Widget : PGtkWidget; data: gPointer) : GBoolean; cdecl;
@@ -3221,7 +3213,7 @@
   R := NormalizeRect(Rect(X1, Y1, X2, Y2));
   if IsRectEmpty(R) then Exit(True);
   with R do
-    TGtk3DeviceContext(DC).drawRect(Left, Top, Right - Left, Bottom - Top, True);
+    TGtk3DeviceContext(DC).drawRect(Left, Top, Right - Left, Bottom - Top, false);
   Result := True;
 end;
 
@@ -3892,7 +3884,7 @@
 function TGtk3WidgetSet.SetWindowOrgEx(dc: hdc; NewX, NewY: Integer;
   OldPoint: PPoint): Boolean;
 var
-  Matrix: Pcairo_matrix_t;
+  Matrix: cairo_matrix_t;
   dx: Double;
   dy: Double;
 begin
@@ -3900,20 +3892,18 @@
   if IsValidDC(DC) then
   begin
     GetWindowOrgEx(dc, OldPoint);
-    New(Matrix);
-    cairo_get_matrix(TGtk3DeviceContext(DC).Widget, Matrix);
-    if Matrix <> nil then
-    begin
-      dx := 0;
-      dy := 0;
-      // cairo_matrix_init_translate(Matrix, -NewX, -NewY);
-      cairo_matrix_translate(Matrix, -NewX, -NewY);
-      cairo_transform(TGtk3DeviceContext(DC).Widget, Matrix);
-      // cairo_set_matrix(TGtk3DeviceContext(DC).Widget, Matrix);
-      // DebugLn('TGtk3WidgetSet.SetWindowOrgEx NewX=',dbgs(NewX),' NewY=',dbgs(NewY));
-      Result := True;
-      Dispose(Matrix);
-    end;
+    cairo_get_matrix(TGtk3DeviceContext(DC).Widget, @Matrix);
+    dx := 0;
+    dy := 0;
+    // cairo_matrix_init_translate(Matrix, -NewX, -NewY);
+    cairo_matrix_translate(@Matrix,
+    	-NewX - TGtk3DeviceContext(DC).fncOrigin.x,
+      -NewY - TGtk3DeviceContext(DC).fncOrigin.Y);
+    cairo_transform(TGtk3DeviceContext(DC).Widget, @Matrix);
+    // cairo_set_matrix(TGtk3DeviceContext(DC).Widget, Matrix);
+    // DebugLn('TGtk3WidgetSet.SetWindowOrgEx NewX=',dbgs(NewX),' NewY=',dbgs(NewY));
+    Result := True;
+
   end;
 end;
 
gtk3up.diff (5,968 bytes)   

Anton Kavalenka

2017-05-21 17:12

reporter   ~0100559

Last edited: 2017-05-21 18:21

View 3 revisions

Patch provided:
* In Tgtk3DeviceContext introduced field fncOrigin which stores initial trasformation for surface. I.e. widgets with menu and toolbars have this.
* GTK3 widgetset implementation uses this in (Get|Set)WindowOrgEx and in LP2DP which also fixes cliprect allocation.

New test provided for nested TWinControl with TGraphicControl inside.

Anton Kavalenka

2017-05-21 17:15

reporter  

laztest103bis.zip (129,660 bytes)

Anton Kavalenka

2017-05-21 17:16

reporter  

Zeljan Rikalo

2017-05-23 10:00

developer   ~0100618

Thanks for the patch. Test and close if ok.

Issue History

Date Modified Username Field Change
2017-05-08 17:33 Anton Kavalenka New Issue
2017-05-08 17:33 Anton Kavalenka File Added: laztest103.zip
2017-05-08 17:33 Anton Kavalenka File Added: gtk3obj.diff
2017-05-08 17:42 Anton Kavalenka File Added: Здымак экрана, 2017-05-08 18-43-00.png
2017-05-08 17:44 Anton Kavalenka Note Added: 0100159
2017-05-08 21:04 Zeljan Rikalo Note Added: 0100161
2017-05-09 09:36 Anton Kavalenka Note Added: 0100173
2017-05-09 10:52 Zeljan Rikalo Note Added: 0100174
2017-05-09 19:51 Anton Kavalenka Note Added: 0100182
2017-05-09 19:51 Anton Kavalenka Note Edited: 0100182 View Revisions
2017-05-09 20:17 Zeljan Rikalo Note Added: 0100184
2017-05-21 17:09 Anton Kavalenka File Added: gtk3up.diff
2017-05-21 17:12 Anton Kavalenka Note Added: 0100559
2017-05-21 17:13 Anton Kavalenka Note Edited: 0100559 View Revisions
2017-05-21 17:15 Anton Kavalenka File Added: laztest103bis.zip
2017-05-21 17:16 Anton Kavalenka File Added: Здымак экрана, 2017-05-21 18-15-39.png
2017-05-21 18:21 Anton Kavalenka Note Edited: 0100559 View Revisions
2017-05-22 10:11 Zeljan Rikalo Assigned To => Zeljan Rikalo
2017-05-22 10:11 Zeljan Rikalo Status new => assigned
2017-05-23 10:00 Zeljan Rikalo Fixed in Revision => 55060
2017-05-23 10:00 Zeljan Rikalo LazTarget => -
2017-05-23 10:00 Zeljan Rikalo Note Added: 0100618
2017-05-23 10:00 Zeljan Rikalo Status assigned => resolved
2017-05-23 10:00 Zeljan Rikalo Resolution open => fixed
2017-05-23 13:54 Anton Kavalenka Status resolved => closed