View Issue Details

IDProjectCategoryView StatusLast Update
0036374LazarusWidgetsetpublic2019-12-11 12:47
ReporterAlexey Tor.Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
PlatformUbuntu 19.10 x64OSOS Version
Product Version2.1 (SVN)Product Build 
Target VersionFixed in Version 
Summary0036374: gtk3: Canvas artifacts, swapped R/B colors
Descriptiondemo attached.
see 2 screens: on gtk2, on gtk3.

- colors are swapped on TextOut, on Ellipse, on Rectangle
- Rectangle is not filled
- triangles have bad colored edges
TagsNo tags attached.
Fixed in Revisionr62356, r62377
LazTarget-
WidgetsetGTK 3
Attached Files
  • gtk2.png (19,987 bytes)
    gtk2.png (19,987 bytes)
  • gtk3.png (21,212 bytes)
    gtk3.png (21,212 bytes)
  • tst-gtk3-artifacts.zip (7,118 bytes)
  • gtk3objects.diff (906 bytes)
    Index: gtk3objects.pas
    ===================================================================
    --- gtk3objects.pas	(revision 62333)
    +++ gtk3objects.pas	(working copy)
    @@ -1422,8 +1422,29 @@
     
     procedure TGtk3DeviceContext.drawEllipse(x: Integer; y: Integer; w: Integer;
       h: Integer);
    +var
    +  save_matrix:cairo_matrix_t;
     begin
    -
    +  cairo_save(Widget);
    +  cairo_get_matrix(Widget, @save_matrix);
    +  cairo_translate (Widget, x + w / 2.0, y + h / 2.0);
    +  cairo_scale (Widget, w / 2.0, h / 2.0);
    +  cairo_new_path(Widget);
    +  cairo_arc
    +      (
    +        (*cr =*) Widget,
    +        (*xc =*) 0,
    +        (*yc =*) 0,
    +        (*radius =*) 1,
    +        (*angle1 =*) 0,
    +        (*angle2 =*) 2 * Pi
    +      );
    +  cairo_close_path(Widget);
    +  ApplyBrush;
    +  cairo_fill_preserve(Widget);
    +  cairo_restore(Widget);
    +  ApplyPen;
    +  cairo_stroke(Widget);
     end;
     
     procedure TGtk3DeviceContext.drawSurface(targetRect: PRect;
    
    gtk3objects.diff (906 bytes)
  • gtk3winapi.inc.diff (1,243 bytes)
    Index: gtk3winapi.inc
    ===================================================================
    --- gtk3winapi.inc	(revision 62333)
    +++ gtk3winapi.inc	(working copy)
    @@ -172,11 +172,14 @@
     
     function TGtk3WidgetSet.ClipboardRegisterFormat(const AMimeType: string
       ): TClipboardFormat;
    +var AtomName: PChar;
     begin
    -  {$IFDEF GTK3DEBUGNOTIMPLEMENTED}
    -  DebugLn('WARNING: TGtk3WidgetSet.ClipboardRegisterFormat not implemented ...');
    -  {$ENDIF}
    -  Result:=inherited ClipboardRegisterFormat(AMimeType);
    +  if Assigned(Application) then begin
    +    AtomName:=PChar(AMimeType);
    +    Result:=ptruint(TGdkAtom.intern(AtomName,False));
    +  end else
    +    RaiseGDBException(
    +      'ERROR: TGtk3WidgetSet.ClipboardRegisterFormat gdk not initialized');
     end;
     
     function TGtk3WidgetSet.CombineRgn(Dest, Src1, Src2: HRGN;
    @@ -1053,10 +1056,8 @@
     
     function TGtk3WidgetSet.Ellipse(DC: HDC; x1, y1, x2, y2: Integer): Boolean;
     begin
    -  {$IFDEF GTK3DEBUGNOTIMPLEMENTED}
    -  DebugLn('WARNING: TGtk3WidgetSet.Ellipse not implemented ...');
    -  {$ENDIF}
    -  Result:=inherited Ellipse(DC, x1, y1, x2, y2);
    +  TGtk3DeviceContext(DC).drawEllipse(x1,y1,x2-x1,y2-y1);
    +  Result:=true;
     end;
     
     function TGtk3WidgetSet.EnableScrollBar(Wnd: HWND; wSBflags, wArrows: Cardinal
    
    gtk3winapi.inc.diff (1,243 bytes)
  • test1.bmp (307,030 bytes)
  • fix1.diff (1,439 bytes)
    Index: lcl/interfaces/gtk3/gtk3objects.pas
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62353)
    +++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
    @@ -1329,17 +1329,15 @@
     begin
       cairo_save(Widget);
       try
    -    applyPen;
    -    // strange about adding +1 -1 to rectangle, but this works ok.
    -    //cairo_rectangle(Widget, x1 + 1, y1 + 1, w - 1, h -1);
    +    ApplyPen;
         cairo_rectangle(Widget, x1, y1, w, h);
    +    cairo_stroke(Widget);
         if AFill then
         begin
    -      cairo_stroke_preserve(Widget);
    -      applyBrush;
    -      cairo_fill_preserve(Widget);
    -    end else
    -      cairo_stroke(Widget);
    +      cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
    +      ApplyBrush;
    +      cairo_fill(Widget);
    +    end;
       finally
         cairo_restore(Widget);
       end;
    Index: lcl/interfaces/gtk3/gtk3winapi.inc
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62353)
    +++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
    @@ -3265,7 +3265,9 @@
       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, false);
    +    TGtk3DeviceContext(DC).drawRect(Left, Top, Right - Left, Bottom - Top,
    +      TGtk3DeviceContext(DC).CurrentBrush.Style<>BS_NULL{bsClear}
    +      );
       Result := True;
     end;
     
    
    fix1.diff (1,439 bytes)
  • tst-gtk3-artifacts-2.zip (6,567 bytes)
  • GTK3_artifact.png (24,272 bytes)
    GTK3_artifact.png (24,272 bytes)
  • fix2.diff (714 bytes)
    Index: lcl/interfaces/gtk3/gtk3objects.pas
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62353)
    +++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
    @@ -1566,7 +1564,7 @@
           cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
     
         cairo_close_path(Widget);
    -    cairo_fill_preserve(Widget);
    +    cairo_fill(Widget);
     
         // now draw the line
         ApplyPen;
    @@ -1575,7 +1573,7 @@
         for i := 1 to NumPts-1 do
           cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
         cairo_close_path(Widget);
    -    cairo_stroke_preserve(Widget);
    +    cairo_stroke(Widget);
       finally
         cairo_restore(Widget);
       end;
    
    fix2.diff (714 bytes)
  • fix3.diff (2,360 bytes)
    Index: lcl/interfaces/gtk3/gtk3objects.pas
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62357)
    +++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
    @@ -234,7 +234,7 @@
         procedure drawText(x: Integer; y: Integer; const s: String); overload;
         procedure drawText(x,y,w,h,flags: Integer; const s: String); overload;
         procedure drawLine(x1: Integer; y1: Integer; x2: Integer; y2: Integer);
    -    procedure drawEllipse(x: Integer; y: Integer; w: Integer; h: Integer);
    +    procedure drawEllipse(x: Integer; y: Integer; w: Integer; h: Integer; AFill: Boolean);
         procedure drawSurface(targetRect: PRect; Surface: Pcairo_surface_t; sourceRect: PRect;
           mask: PGdkPixBuf; maskRect: PRect);
         procedure drawImage(targetRect: PRect; image: PGdkPixBuf; sourceRect: PRect;
    @@ -1419,7 +1419,7 @@
     end;
     
     procedure TGtk3DeviceContext.drawEllipse(x: Integer; y: Integer; w: Integer;
    -  h: Integer);
    +  h: Integer; AFill: Boolean);
     var
       save_matrix:cairo_matrix_t;
     begin
    @@ -1438,8 +1438,11 @@
             (*angle2 =*) 2 * Pi
           );
       cairo_close_path(Widget);
    -  ApplyBrush;
    -  cairo_fill_preserve(Widget);
    +  if AFill then
    +  begin
    +    ApplyBrush;
    +    cairo_fill_preserve(Widget);
    +  end;
       cairo_restore(Widget);
       ApplyPen;
       cairo_stroke(Widget);
    @@ -1585,7 +1588,7 @@
           cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
     
         cairo_close_path(Widget);
    -    cairo_fill_preserve(Widget);
    +    cairo_fill(Widget);
     
         // now draw the line
         ApplyPen;
    @@ -1594,7 +1597,7 @@
         for i := 1 to NumPts-1 do
           cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
         cairo_close_path(Widget);
    -    cairo_stroke_preserve(Widget);
    +    cairo_stroke(Widget);
       finally
         cairo_restore(Widget);
       end;
    Index: lcl/interfaces/gtk3/gtk3winapi.inc
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62357)
    +++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
    @@ -1053,7 +1053,8 @@
     
     function TGtk3WidgetSet.Ellipse(DC: HDC; x1, y1, x2, y2: Integer): Boolean;
     begin
    -  TGtk3DeviceContext(DC).drawEllipse(x1,y1,x2-x1,y2-y1);
    +  TGtk3DeviceContext(DC).drawEllipse(x1,y1,x2-x1,y2-y1,
    +    TGtk3DeviceContext(DC).CurrentBrush.Style<>BS_NULL);
       Result:=true;
     end;
     
    
    fix3.diff (2,360 bytes)
  • fix4.diff (3,644 bytes)
    Index: lcl/interfaces/gtk3/gtk3objects.pas
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62357)
    +++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
    @@ -234,7 +234,7 @@
         procedure drawText(x: Integer; y: Integer; const s: String); overload;
         procedure drawText(x,y,w,h,flags: Integer; const s: String); overload;
         procedure drawLine(x1: Integer; y1: Integer; x2: Integer; y2: Integer);
    -    procedure drawEllipse(x: Integer; y: Integer; w: Integer; h: Integer);
    +    procedure drawEllipse(x: Integer; y: Integer; w: Integer; h: Integer; AFill: Boolean);
         procedure drawSurface(targetRect: PRect; Surface: Pcairo_surface_t; sourceRect: PRect;
           mask: PGdkPixBuf; maskRect: PRect);
         procedure drawImage(targetRect: PRect; image: PGdkPixBuf; sourceRect: PRect;
    @@ -1330,11 +1330,11 @@
       cairo_save(Widget);
       try
         ApplyPen;
    -    cairo_rectangle(Widget, x1, y1, w, h);
    +    cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
         cairo_stroke(Widget);
         if AFill then
         begin
    -      cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
    +      cairo_rectangle(Widget, x1, y1, w - 2, h - 2);
           ApplyBrush;
           cairo_fill(Widget);
         end;
    @@ -1419,7 +1419,7 @@
     end;
     
     procedure TGtk3DeviceContext.drawEllipse(x: Integer; y: Integer; w: Integer;
    -  h: Integer);
    +  h: Integer; AFill: Boolean);
     var
       save_matrix:cairo_matrix_t;
     begin
    @@ -1438,8 +1438,11 @@
             (*angle2 =*) 2 * Pi
           );
       cairo_close_path(Widget);
    -  ApplyBrush;
    -  cairo_fill_preserve(Widget);
    +  if AFill then
    +  begin
    +    ApplyBrush;
    +    cairo_fill_preserve(Widget);
    +  end;
       cairo_restore(Widget);
       ApplyPen;
       cairo_stroke(Widget);
    @@ -1585,7 +1588,7 @@
           cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
     
         cairo_close_path(Widget);
    -    cairo_fill_preserve(Widget);
    +    cairo_fill(Widget);
     
         // now draw the line
         ApplyPen;
    @@ -1594,7 +1597,7 @@
         for i := 1 to NumPts-1 do
           cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
         cairo_close_path(Widget);
    -    cairo_stroke_preserve(Widget);
    +    cairo_stroke(Widget);
       finally
         cairo_restore(Widget);
       end;
    @@ -1677,7 +1680,7 @@
       end;
     
       applyBrush;
    -  cairo_rectangle(Widget, x, y, w, h);
    +  cairo_rectangle(Widget, x, y, w - 1, h - 1);
       cairo_stroke_preserve(Widget);
       cairo_fill(Widget);
       // cairo_clip(Widget);
    Index: lcl/interfaces/gtk3/gtk3winapi.inc
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62357)
    +++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
    @@ -1053,7 +1053,9 @@
     
     function TGtk3WidgetSet.Ellipse(DC: HDC; x1, y1, x2, y2: Integer): Boolean;
     begin
    -  TGtk3DeviceContext(DC).drawEllipse(x1,y1,x2-x1,y2-y1);
    +  TGtk3DeviceContext(DC).drawEllipse(
    +    x1, y1, x2-x1-1, y2-y1-1,
    +    TGtk3DeviceContext(DC).CurrentBrush.Style<>BS_NULL);
       Result:=true;
     end;
     
    @@ -1694,8 +1696,7 @@
     
     end;
     
    -function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH
    -  ): Integer;
    +function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH): Integer;
     var
       cr: Pcairo_t;
     begin
    @@ -1706,7 +1707,7 @@
       if not IsValidDC(DC) then
         exit;
       cr := TGtk3DeviceContext(DC).Widget;
    -  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left, ARect.Bottom-ARect.Top);
    +  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
       if IsValidGDIObject(hBr) then
         TGtk3DeviceContext(DC).SetSourceColor(TGtk3Brush(HBR).Color);
       cairo_set_line_width(cr, 1);
    
    fix4.diff (3,644 bytes)
  • fix5.diff (6,365 bytes)
    Index: lcl/interfaces/gtk3/gtk3objects.pas
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62364)
    +++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
    @@ -229,12 +229,12 @@
         procedure DeleteObjects;
       public
         procedure drawPoint(x1: Integer; y1: Integer);
    -    procedure drawRect(x1: Integer; y1: Integer; w: Integer; h: Integer; const AFill: Boolean);
    +    procedure drawRect(x1, y1, w, h: Integer; const AFill: Boolean);
         procedure drawRoundRect(x, y, w, h, rx, ry: Integer);
         procedure drawText(x: Integer; y: Integer; const s: String); overload;
         procedure drawText(x,y,w,h,flags: Integer; const s: String); overload;
         procedure drawLine(x1: Integer; y1: Integer; x2: Integer; y2: Integer);
    -    procedure drawEllipse(x: Integer; y: Integer; w: Integer; h: Integer);
    +    procedure drawEllipse(x, y, w, h: Integer; AFill: Boolean);
         procedure drawSurface(targetRect: PRect; Surface: Pcairo_surface_t; sourceRect: PRect;
           mask: PGdkPixBuf; maskRect: PRect);
         procedure drawImage(targetRect: PRect; image: PGdkPixBuf; sourceRect: PRect;
    @@ -243,7 +243,7 @@
           mask: PGdkPixBuf; maskRect: PRect);
         procedure drawPixmap(p: PPoint; pm: PGdkPixbuf; sr: PRect);
         procedure drawPolyLine(P: PPoint; NumPts: Integer);
    -    procedure drawPolygon(P: PPoint; NumPts: Integer; FillRule: integer);
    +    procedure drawPolygon(P: PPoint; NumPts: Integer; FillRule: Integer; AFill: Boolean);
         procedure drawPolyBezier(P: PPoint; NumPoints: Integer; Filled, Continuous: boolean);
         procedure EllipseArcPath(CX, CY, RX, RY: Double; Angle1, Angle2: Double; Clockwise, Continuous: Boolean);
         procedure eraseRect(ARect: PRect);
    @@ -1324,14 +1324,10 @@
       cairo_stroke(Widget);
     end;
     
    -procedure TGtk3DeviceContext.drawRect(x1: Integer; y1: Integer; w: Integer;
    -  h: Integer; const AFill: Boolean);
    +procedure TGtk3DeviceContext.drawRect(x1, y1, w, h: Integer; const AFill: Boolean);
     begin
       cairo_save(Widget);
       try
    -    ApplyPen;
    -    cairo_rectangle(Widget, x1, y1, w, h);
    -    cairo_stroke(Widget);
         if AFill then
         begin
           cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
    @@ -1338,6 +1334,10 @@
           ApplyBrush;
           cairo_fill(Widget);
         end;
    +
    +    ApplyPen;
    +    cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
    +    cairo_stroke(Widget);
       finally
         cairo_restore(Widget);
       end;
    @@ -1418,8 +1418,7 @@
       cairo_line_to(Widget, x2, y2);
     end;
     
    -procedure TGtk3DeviceContext.drawEllipse(x: Integer; y: Integer; w: Integer;
    -  h: Integer);
    +procedure TGtk3DeviceContext.drawEllipse(x, y, w, h: Integer; AFill: Boolean);
     var
       save_matrix:cairo_matrix_t;
     begin
    @@ -1438,8 +1437,11 @@
             (*angle2 =*) 2 * Pi
           );
       cairo_close_path(Widget);
    -  ApplyBrush;
    -  cairo_fill_preserve(Widget);
    +  if AFill then
    +  begin
    +    ApplyBrush;
    +    cairo_fill_preserve(Widget);
    +  end;
       cairo_restore(Widget);
       ApplyPen;
       cairo_stroke(Widget);
    @@ -1568,7 +1570,7 @@
     end;
     
     procedure TGtk3DeviceContext.drawPolygon(P: PPoint; NumPts: Integer;
    -  FillRule: integer);
    +  FillRule: Integer; AFill: Boolean);
     var
       i: Integer;
     const
    @@ -1576,6 +1578,8 @@
     begin
       cairo_save(Widget);
       try
    +   if AFill then
    +   begin
         // first apply the fill because the line is drawn over the filled area after
         applyBrush;
         cairo_set_fill_rule(Widget, cairo_fill_rule_t(FillRule));
    @@ -1585,9 +1589,9 @@
           cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
     
         cairo_close_path(Widget);
    -    cairo_fill_preserve(Widget);
    +    cairo_fill(Widget);
    +   end;
     
    -    // now draw the line
         ApplyPen;
         //cairo_set_antialias(widget, CAIRO_ANTIALIAS_SUBPIXEL);
         cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
    @@ -1594,7 +1598,7 @@
         for i := 1 to NumPts-1 do
           cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
         cairo_close_path(Widget);
    -    cairo_stroke_preserve(Widget);
    +    cairo_stroke(Widget);
       finally
         cairo_restore(Widget);
       end;
    @@ -1677,7 +1681,7 @@
       end;
     
       applyBrush;
    -  cairo_rectangle(Widget, x, y, w, h);
    +  cairo_rectangle(Widget, x, y, w - 1, h - 1);
       cairo_stroke_preserve(Widget);
       cairo_fill(Widget);
       // cairo_clip(Widget);
    Index: lcl/interfaces/gtk3/gtk3winapi.inc
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62364)
    +++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
    @@ -1052,9 +1052,12 @@
     end;
     
     function TGtk3WidgetSet.Ellipse(DC: HDC; x1, y1, x2, y2: Integer): Boolean;
    +var
    +  bFill: Boolean;
     begin
    -  TGtk3DeviceContext(DC).drawEllipse(x1,y1,x2-x1,y2-y1);
    -  Result:=true;
    +  bFill := TGtk3DeviceContext(DC).CurrentBrush.Style <> BS_NULL;
    +  TGtk3DeviceContext(DC).drawEllipse(x1, y1, x2 - x1 - 1, y2 - y1 - 1, bFill);
    +  Result := True;
     end;
     
     function TGtk3WidgetSet.EnableScrollBar(Wnd: HWND; wSBflags, wArrows: Cardinal
    @@ -1694,8 +1697,7 @@
     
     end;
     
    -function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH
    -  ): Integer;
    +function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH): Integer;
     var
       cr: Pcairo_t;
     begin
    @@ -1706,7 +1708,7 @@
       if not IsValidDC(DC) then
         exit;
       cr := TGtk3DeviceContext(DC).Widget;
    -  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left, ARect.Bottom-ARect.Top);
    +  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
       if IsValidGDIObject(hBr) then
         TGtk3DeviceContext(DC).SetSourceColor(TGtk3Brush(HBR).Color);
       cairo_set_line_width(cr, 1);
    @@ -3143,13 +3145,18 @@
     
     function TGtk3WidgetSet.Polygon(DC: HDC; Points: PPoint; NumPts: Integer;
       Winding: boolean): boolean;
    +var
    +  NFillRule: integer;
    +  bFill: boolean;
     begin
       if not IsValidDC(DC) then
         exit(False);
    -  if not Winding then // faster
    -    TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, ord(CAIRO_FILL_RULE_EVEN_ODD))
    +  if Winding then
    +    NFillRule := Ord(CAIRO_FILL_RULE_WINDING)
       else
    -    TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, Ord(CAIRO_FILL_RULE_WINDING));
    +    NFillRule := Ord(CAIRO_FILL_RULE_EVEN_ODD);
    +  bFill := TGtk3DeviceContext(DC).CurrentBrush.Style <> BS_NULL;
    +  TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, NFillRule, bFill);
       Result:= True;
     end;
     
    
    fix5.diff (6,365 bytes)
  • fix6.diff (10,931 bytes)
    Index: lcl/interfaces/gtk3/gtk3objects.pas
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62364)
    +++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
    @@ -229,12 +229,12 @@
         procedure DeleteObjects;
       public
         procedure drawPoint(x1: Integer; y1: Integer);
    -    procedure drawRect(x1: Integer; y1: Integer; w: Integer; h: Integer; const AFill: Boolean);
    +    procedure drawRect(x1, y1, w, h: Integer; const AFill, ABorder: Boolean);
         procedure drawRoundRect(x, y, w, h, rx, ry: Integer);
         procedure drawText(x: Integer; y: Integer; const s: String); overload;
         procedure drawText(x,y,w,h,flags: Integer; const s: String); overload;
         procedure drawLine(x1: Integer; y1: Integer; x2: Integer; y2: Integer);
    -    procedure drawEllipse(x: Integer; y: Integer; w: Integer; h: Integer);
    +    procedure drawEllipse(x, y, w, h: Integer; AFill, ABorder: Boolean);
         procedure drawSurface(targetRect: PRect; Surface: Pcairo_surface_t; sourceRect: PRect;
           mask: PGdkPixBuf; maskRect: PRect);
         procedure drawImage(targetRect: PRect; image: PGdkPixBuf; sourceRect: PRect;
    @@ -243,7 +243,8 @@
           mask: PGdkPixBuf; maskRect: PRect);
         procedure drawPixmap(p: PPoint; pm: PGdkPixbuf; sr: PRect);
         procedure drawPolyLine(P: PPoint; NumPts: Integer);
    -    procedure drawPolygon(P: PPoint; NumPts: Integer; FillRule: integer);
    +    procedure drawPolygon(P: PPoint; NumPts: Integer; FillRule: Integer; AFill,
    +      ABorder: Boolean);
         procedure drawPolyBezier(P: PPoint; NumPoints: Integer; Filled, Continuous: boolean);
         procedure EllipseArcPath(CX, CY, RX, RY: Double; Angle1, Angle2: Double; Clockwise, Continuous: Boolean);
         procedure eraseRect(ARect: PRect);
    @@ -1324,14 +1325,10 @@
       cairo_stroke(Widget);
     end;
     
    -procedure TGtk3DeviceContext.drawRect(x1: Integer; y1: Integer; w: Integer;
    -  h: Integer; const AFill: Boolean);
    +procedure TGtk3DeviceContext.drawRect(x1, y1, w, h: Integer; const AFill, ABorder: Boolean);
     begin
       cairo_save(Widget);
       try
    -    ApplyPen;
    -    cairo_rectangle(Widget, x1, y1, w, h);
    -    cairo_stroke(Widget);
         if AFill then
         begin
           cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
    @@ -1338,6 +1335,12 @@
           ApplyBrush;
           cairo_fill(Widget);
         end;
    +    if ABorder then
    +    begin
    +      ApplyPen;
    +      cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
    +      cairo_stroke(Widget);
    +    end;
       finally
         cairo_restore(Widget);
       end;
    @@ -1407,7 +1410,6 @@
       finally
         cairo_restore(Widget);
       end;
    -
     end;
     
     procedure TGtk3DeviceContext.drawLine(x1: Integer; y1: Integer; x2: Integer;
    @@ -1418,31 +1420,41 @@
       cairo_line_to(Widget, x2, y2);
     end;
     
    -procedure TGtk3DeviceContext.drawEllipse(x: Integer; y: Integer; w: Integer;
    -  h: Integer);
    +procedure TGtk3DeviceContext.drawEllipse(x, y, w, h: Integer; AFill, ABorder: Boolean);
     var
       save_matrix:cairo_matrix_t;
     begin
       cairo_save(Widget);
    -  cairo_get_matrix(Widget, @save_matrix);
    -  cairo_translate (Widget, x + w / 2.0, y + h / 2.0);
    -  cairo_scale (Widget, w / 2.0, h / 2.0);
    +  try
    +    cairo_get_matrix(Widget, @save_matrix);
    +    cairo_translate (Widget, x + w / 2.0, y + h / 2.0);
    +    cairo_scale (Widget, w / 2.0, h / 2.0);
    +    cairo_new_path(Widget);
    +    cairo_arc
    +        (
    +          (*cr =*) Widget,
    +          (*xc =*) 0,
    +          (*yc =*) 0,
    +          (*radius =*) 1,
    +          (*angle1 =*) 0,
    +          (*angle2 =*) 2 * Pi
    +        );
    +    cairo_close_path(Widget);
    +    if AFill then
    +    begin
    +      ApplyBrush;
    +      cairo_fill_preserve(Widget);
    +    end;
    +  finally
    +    cairo_restore(Widget);
    +  end;
    +  if ABorder then
    +  begin
    +    ApplyPen;
    +    cairo_stroke(Widget);
    +  end;
    +  //if ABorder=false, need to clear current path
       cairo_new_path(Widget);
    -  cairo_arc
    -      (
    -        (*cr =*) Widget,
    -        (*xc =*) 0,
    -        (*yc =*) 0,
    -        (*radius =*) 1,
    -        (*angle1 =*) 0,
    -        (*angle2 =*) 2 * Pi
    -      );
    -  cairo_close_path(Widget);
    -  ApplyBrush;
    -  cairo_fill_preserve(Widget);
    -  cairo_restore(Widget);
    -  ApplyPen;
    -  cairo_stroke(Widget);
     end;
     
     procedure TGtk3DeviceContext.drawSurface(targetRect: PRect;
    @@ -1568,7 +1580,7 @@
     end;
     
     procedure TGtk3DeviceContext.drawPolygon(P: PPoint; NumPts: Integer;
    -  FillRule: integer);
    +  FillRule: Integer; AFill, ABorder: Boolean);
     var
       i: Integer;
     const
    @@ -1576,25 +1588,28 @@
     begin
       cairo_save(Widget);
       try
    -    // first apply the fill because the line is drawn over the filled area after
    -    applyBrush;
    -    cairo_set_fill_rule(Widget, cairo_fill_rule_t(FillRule));
    -    // + Offset is so the center of the pixel is used.
    -    cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
    -    for i := 1 to NumPts-1 do
    -      cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
    +    if AFill then
    +    begin
    +      // first apply the fill because the line is drawn over the filled area after
    +      ApplyBrush;
    +      cairo_set_fill_rule(Widget, cairo_fill_rule_t(FillRule));
    +      // + Offset is so the center of the pixel is used.
    +      cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
    +      for i := 1 to NumPts-1 do
    +        cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
    +      cairo_close_path(Widget);
    +      cairo_fill(Widget);
    +    end;
     
    -    cairo_close_path(Widget);
    -    cairo_fill_preserve(Widget);
    -
    -    // now draw the line
    -    ApplyPen;
    -    //cairo_set_antialias(widget, CAIRO_ANTIALIAS_SUBPIXEL);
    -    cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
    -    for i := 1 to NumPts-1 do
    -      cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
    -    cairo_close_path(Widget);
    -    cairo_stroke_preserve(Widget);
    +    if ABorder then
    +    begin
    +      ApplyPen;
    +      cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
    +      for i := 1 to NumPts-1 do
    +        cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
    +      cairo_close_path(Widget);
    +      cairo_stroke(Widget);
    +    end;
       finally
         cairo_restore(Widget);
       end;
    @@ -1657,10 +1672,9 @@
     
     procedure TGtk3DeviceContext.fillRect(x, y, w, h: Integer; ABrush: HBRUSH);
     var
    -  devx, devy, dx, dy, dw, dh: Double;
    -  ATarget: Pcairo_surface_t;
    -  ANewSurface: Pcairo_surface_t;
    -  ACairo: Pcairo_t;
    +  //devx, devy, dx, dy, dw, dh: Double;
    +  //ATarget: Pcairo_surface_t;
    +  //ANewSurface: Pcairo_surface_t;
       ATempBrush: TGtk3Brush;
     begin
       {$ifdef VerboseGtk3DeviceContext}
    @@ -1668,24 +1682,24 @@
       {$endif}
     
       cairo_save(Widget);
    -  ATempBrush := nil;
    -  if ABrush <> 0 then
    -  begin
    -    ATempBrush := FCurrentBrush;
    -    fBkMode:=OPAQUE;
    -    SetCurrentBrush(TGtk3Brush(ABrush));
    -  end;
    +  try
    +    ATempBrush := nil;
    +    if ABrush <> 0 then
    +    begin
    +      ATempBrush := FCurrentBrush;
    +      fBkMode:=OPAQUE;
    +      SetCurrentBrush(TGtk3Brush(ABrush));
    +    end;
     
    -  applyBrush;
    -  cairo_rectangle(Widget, x, y, w, h);
    -  cairo_stroke_preserve(Widget);
    -  cairo_fill(Widget);
    -  // cairo_clip(Widget);
    +    applyBrush;
    +    cairo_rectangle(Widget, x, y, w - 1, h - 1);
    +    cairo_fill(Widget);
     
    -  // cairo_fill_preserve(Widget);
    -  if ABrush <> 0 then
    -    SetCurrentBrush(ATempBrush);
    -  cairo_restore(Widget);
    +    if ABrush <> 0 then
    +      SetCurrentBrush(ATempBrush);
    +  finally
    +    cairo_restore(Widget);
    +  end;
     
       // ATarget := cairo_get_target(Widget);
       (*
    Index: lcl/interfaces/gtk3/gtk3widgets.pas
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3widgets.pas	(revision 62364)
    +++ lcl/interfaces/gtk3/gtk3widgets.pas	(working copy)
    @@ -3079,7 +3079,7 @@
       end;
     
       if BorderStyle <> bsNone then
    -    DC.drawRect(0, 0, LCLObject.Width, LCLObject.Height, LCLObject.Color <> clDefault);
    +    DC.drawRect(0, 0, LCLObject.Width, LCLObject.Height, LCLObject.Color <> clDefault, True);
     end;
     
     function TGtk3Panel.getText: String;
    Index: lcl/interfaces/gtk3/gtk3winapi.inc
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62364)
    +++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
    @@ -1052,9 +1052,13 @@
     end;
     
     function TGtk3WidgetSet.Ellipse(DC: HDC; x1, y1, x2, y2: Integer): Boolean;
    +var
    +  bFill, bBorder: Boolean;
     begin
    -  TGtk3DeviceContext(DC).drawEllipse(x1,y1,x2-x1,y2-y1);
    -  Result:=true;
    +  bFill := TGtk3DeviceContext(DC).CurrentBrush.Style <> BS_NULL;
    +  bBorder := TGtk3DeviceContext(DC).CurrentPen.Style <> psClear;
    +  TGtk3DeviceContext(DC).drawEllipse(x1, y1, x2 - x1 - 1, y2 - y1 - 1, bFill, bBorder);
    +  Result := True;
     end;
     
     function TGtk3WidgetSet.EnableScrollBar(Wnd: HWND; wSBflags, wArrows: Cardinal
    @@ -1694,8 +1698,7 @@
     
     end;
     
    -function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH
    -  ): Integer;
    +function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH): Integer;
     var
       cr: Pcairo_t;
     begin
    @@ -1706,7 +1709,7 @@
       if not IsValidDC(DC) then
         exit;
       cr := TGtk3DeviceContext(DC).Widget;
    -  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left, ARect.Bottom-ARect.Top);
    +  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
       if IsValidGDIObject(hBr) then
         TGtk3DeviceContext(DC).SetSourceColor(TGtk3Brush(HBR).Color);
       cairo_set_line_width(cr, 1);
    @@ -3143,13 +3146,19 @@
     
     function TGtk3WidgetSet.Polygon(DC: HDC; Points: PPoint; NumPts: Integer;
       Winding: boolean): boolean;
    +var
    +  NFillRule: integer;
    +  bFill, bBorder: boolean;
     begin
       if not IsValidDC(DC) then
         exit(False);
    -  if not Winding then // faster
    -    TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, ord(CAIRO_FILL_RULE_EVEN_ODD))
    +  if Winding then
    +    NFillRule := Ord(CAIRO_FILL_RULE_WINDING)
       else
    -    TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, Ord(CAIRO_FILL_RULE_WINDING));
    +    NFillRule := Ord(CAIRO_FILL_RULE_EVEN_ODD);
    +  bFill := TGtk3DeviceContext(DC).CurrentBrush.Style <> BS_NULL;
    +  bBorder := TGtk3DeviceContext(DC).CurrentPen.Style <> psClear;
    +  TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, NFillRule, bFill, bBorder);
       Result:= True;
     end;
     
    @@ -3257,15 +3266,15 @@
     function TGtk3WidgetSet.Rectangle(DC: HDC; X1, Y1, X2, Y2: Integer): Boolean;
     var
       R: TRect;
    +  bFill, bBorder: Boolean;
     begin
       if not IsValidDC(DC) then
         exit(False);
       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,
    -      TGtk3DeviceContext(DC).CurrentBrush.Style<>BS_NULL{bsClear}
    -      );
    +  bFill := TGtk3DeviceContext(DC).CurrentBrush.Style <> BS_NULL;
    +  bBorder := TGtk3DeviceContext(DC).CurrentPen.Style <> psClear;
    +  TGtk3DeviceContext(DC).drawRect(R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top, bFill, bBorder);
       Result := True;
     end;
     
    
    fix6.diff (10,931 bytes)
  • gtk3winapi.diff (858 bytes)
    Index: lcl/interfaces/gtk3/gtk3winapi.inc
    ===================================================================
    --- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62372)
    +++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
    @@ -4073,8 +4073,13 @@
       {$ENDIF}
       ATargetRect := Rect(X, Y, Width + X, Height + Y);
       ASrcRect := Rect(XSrc, YSrc, SrcWidth + XSrc, SrcHeight + YSrc);
    -  DestContext.drawImage1(@ATargetRect, PgdkPixbuf(SrcContext.CurrentImage.Handle) , @ASrcRect, nil, nil);
    -  // Result := True;
    +
    +  if (DestContext.OwnsSurface) then
    +    DestContext.drawImage1(@ATargetRect, PgdkPixbuf(SrcContext.CurrentImage.Handle) , @ASrcRect, nil, nil)
    +  else
    +    DestContext.drawSurface(@ATargetRect,SrcContext.CairoSurface , @ASrcRect, nil, nil);
    +
    +  Result := True;
     end;
     
     function TGtk3WidgetSet.SystemParametersInfo(uiAction: DWord; uiParam: DWord;
    
    gtk3winapi.diff (858 bytes)

Relationships

related to 0036254 resolvedJuha Manninen gtk3: PNG images render badly 

Activities

Alexey Tor.

2019-11-28 20:24

reporter  

gtk2.png (19,987 bytes)
gtk2.png (19,987 bytes)
gtk3.png (21,212 bytes)
gtk3.png (21,212 bytes)

Alexey Tor.

2019-11-28 20:24

reporter  

tst-gtk3-artifacts.zip (7,118 bytes)

Anton Kavalenka

2019-12-07 10:36

reporter   ~0119673

Implement filled ellipse painting in cairo-way.

Rectangle IMO should not be filled, it is GTK2 bug, not GTK3. That purpose the Fillrect() intended.

gtk3objects.diff (906 bytes)
Index: gtk3objects.pas
===================================================================
--- gtk3objects.pas	(revision 62333)
+++ gtk3objects.pas	(working copy)
@@ -1422,8 +1422,29 @@
 
 procedure TGtk3DeviceContext.drawEllipse(x: Integer; y: Integer; w: Integer;
   h: Integer);
+var
+  save_matrix:cairo_matrix_t;
 begin
-
+  cairo_save(Widget);
+  cairo_get_matrix(Widget, @save_matrix);
+  cairo_translate (Widget, x + w / 2.0, y + h / 2.0);
+  cairo_scale (Widget, w / 2.0, h / 2.0);
+  cairo_new_path(Widget);
+  cairo_arc
+      (
+        (*cr =*) Widget,
+        (*xc =*) 0,
+        (*yc =*) 0,
+        (*radius =*) 1,
+        (*angle1 =*) 0,
+        (*angle2 =*) 2 * Pi
+      );
+  cairo_close_path(Widget);
+  ApplyBrush;
+  cairo_fill_preserve(Widget);
+  cairo_restore(Widget);
+  ApplyPen;
+  cairo_stroke(Widget);
 end;
 
 procedure TGtk3DeviceContext.drawSurface(targetRect: PRect;
gtk3objects.diff (906 bytes)
gtk3winapi.inc.diff (1,243 bytes)
Index: gtk3winapi.inc
===================================================================
--- gtk3winapi.inc	(revision 62333)
+++ gtk3winapi.inc	(working copy)
@@ -172,11 +172,14 @@
 
 function TGtk3WidgetSet.ClipboardRegisterFormat(const AMimeType: string
   ): TClipboardFormat;
+var AtomName: PChar;
 begin
-  {$IFDEF GTK3DEBUGNOTIMPLEMENTED}
-  DebugLn('WARNING: TGtk3WidgetSet.ClipboardRegisterFormat not implemented ...');
-  {$ENDIF}
-  Result:=inherited ClipboardRegisterFormat(AMimeType);
+  if Assigned(Application) then begin
+    AtomName:=PChar(AMimeType);
+    Result:=ptruint(TGdkAtom.intern(AtomName,False));
+  end else
+    RaiseGDBException(
+      'ERROR: TGtk3WidgetSet.ClipboardRegisterFormat gdk not initialized');
 end;
 
 function TGtk3WidgetSet.CombineRgn(Dest, Src1, Src2: HRGN;
@@ -1053,10 +1056,8 @@
 
 function TGtk3WidgetSet.Ellipse(DC: HDC; x1, y1, x2, y2: Integer): Boolean;
 begin
-  {$IFDEF GTK3DEBUGNOTIMPLEMENTED}
-  DebugLn('WARNING: TGtk3WidgetSet.Ellipse not implemented ...');
-  {$ENDIF}
-  Result:=inherited Ellipse(DC, x1, y1, x2, y2);
+  TGtk3DeviceContext(DC).drawEllipse(x1,y1,x2-x1,y2-y1);
+  Result:=true;
 end;
 
 function TGtk3WidgetSet.EnableScrollBar(Wnd: HWND; wSBflags, wArrows: Cardinal
gtk3winapi.inc.diff (1,243 bytes)

Juha Manninen

2019-12-07 12:16

developer   ~0119678

Last edited: 2019-12-07 12:38

View 3 revisions

Here it does not compile. I get:
 gtk3winapi.inc(179,13) Error: Illegal type conversion: "TGdkAtom" to "QWord"
from line:
    Result:=ptruint(TGdkAtom.intern(AtomName,False));
I use FPC trunk from ~ 2 months ago on a 64-bit Linux.
Strange because
  TGdkAtom = object
which should have the same size as ptruint.
[Edit] No, actually the "object" is a nasty beast. It is like a record. I have never used it in my own code and was hoping to avoid it.
Size of this TGdkAtom thing is 0 because it has no data elements. It only has functions.
How did it compile for you?

BTW, creating patches from the top level directory of Lazarus sources would be even better. Just a small convenience thing...

Juha Manninen

2019-12-07 12:51

developer   ~0119679

TGdkAtom = object
    function name: Pgchar; cdecl; inline;
    function intern(atom_name: Pgchar; only_if_exists: gboolean): TGdkAtom; cdecl; inline; static;
    function intern_static_string(atom_name: Pgchar): TGdkAtom; cdecl; inline; static;
  end;

How can the function intern() return a TGdkAtom? Should it be PGdkAtom? How can TGdkAtom work in other parts of GTK3 binding code?
I think using the "object" syntax for LCL-GTK3 was a mistake. Does it really save memory? It has a "Self" pointer anyway for local data.

Anton Kavalenka

2019-12-07 13:34

reporter   ~0119680

@Juha Manninen
please drop out this clipboard-related code - this is another issue or update functions to return PGdkAtom

But using object as GTK handle wrapper - is a nice idea invented by @Zeljan Rikalo
this make gtk3-related code look object-oriented as it intended to be.

Alexey Tor.

2019-12-07 15:32

reporter   ~0119681

Anton,
we have 3 methods for rectangle:
- FillRect - fill inside, no frame
- Rectangle - fill inside + frame
- FrameRect - frame only

gtk2 is OK

Juha Manninen

2019-12-07 15:42

developer   ~0119682

> please drop out this clipboard-related code
Ok, I did that and now the code compiles but makes no difference for Alexey's test project. The colors are still wrong.

Anton Kavalenka

2019-12-07 19:14

reporter   ~0119684

New code uses single arc path instead of 4 Busier's curves inherited from Widgetset.

Anton Kavalenka

2019-12-07 19:34

reporter   ~0119685

Saving to bitmap at the end of method TForm1.PaintBitmap worked properly

Actual colour swapping take place in TCanvas,Draw()

test1.bmp (307,030 bytes)

Juha Manninen

2019-12-07 21:47

developer   ~0119686

> Saving to bitmap at the end of method TForm1.PaintBitmap worked properly

Saving where? I understood the bitmap is drawn in memory. Can somebody please provide a test project that shows the issue by simply running it?

Alexey Tor.

2019-12-08 14:42

reporter   ~0119694

fix1.diff-- makes Rectangle filled (if Brush.Style=bsSolid); and fixes this filling so 1 px frame is visible.

fix1.diff (1,439 bytes)
Index: lcl/interfaces/gtk3/gtk3objects.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62353)
+++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
@@ -1329,17 +1329,15 @@
 begin
   cairo_save(Widget);
   try
-    applyPen;
-    // strange about adding +1 -1 to rectangle, but this works ok.
-    //cairo_rectangle(Widget, x1 + 1, y1 + 1, w - 1, h -1);
+    ApplyPen;
     cairo_rectangle(Widget, x1, y1, w, h);
+    cairo_stroke(Widget);
     if AFill then
     begin
-      cairo_stroke_preserve(Widget);
-      applyBrush;
-      cairo_fill_preserve(Widget);
-    end else
-      cairo_stroke(Widget);
+      cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
+      ApplyBrush;
+      cairo_fill(Widget);
+    end;
   finally
     cairo_restore(Widget);
   end;
Index: lcl/interfaces/gtk3/gtk3winapi.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62353)
+++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
@@ -3265,7 +3265,9 @@
   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, false);
+    TGtk3DeviceContext(DC).drawRect(Left, Top, Right - Left, Bottom - Top,
+      TGtk3DeviceContext(DC).CurrentBrush.Style<>BS_NULL{bsClear}
+      );
   Result := True;
 end;
 
fix1.diff (1,439 bytes)

Alexey Tor.

2019-12-08 14:50

reporter   ~0119695

Here is updated demo, which shows more info about colors and FillRect/FrameRect.

tst-gtk3-artifacts-2.zip (6,567 bytes)

Juha Manninen

2019-12-08 16:45

developer   ~0119696

Last edited: 2019-12-08 20:48

View 2 revisions

The text colors are still wrong. I applied also the latest patch from Alexey and use his latest test application.
I attach a screenshot of the app window.
I don't know what you guys are up to. I would love to apply a working patch but now I feel like wasting my time.

[Edit] Ok, oops, I figured out the patches didn't try to fix the text color issue. I applied the patches in r62356. This report will stay open because the text color is an important part.



GTK3_artifact.png (24,272 bytes)
GTK3_artifact.png (24,272 bytes)

Alexey Tor.

2019-12-08 21:28

reporter   ~0119701

i fixed the redundant edges of polygons (triangles).
is it ok fix? i changed "_preserve" functions in 2 places to normal funcs, so previous "path" is erased and edges are cleared.

fix2.diff (714 bytes)
Index: lcl/interfaces/gtk3/gtk3objects.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62353)
+++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
@@ -1566,7 +1564,7 @@
       cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
 
     cairo_close_path(Widget);
-    cairo_fill_preserve(Widget);
+    cairo_fill(Widget);
 
     // now draw the line
     ApplyPen;
@@ -1575,7 +1573,7 @@
     for i := 1 to NumPts-1 do
       cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
     cairo_close_path(Widget);
-    cairo_stroke_preserve(Widget);
+    cairo_stroke(Widget);
   finally
     cairo_restore(Widget);
   end;
fix2.diff (714 bytes)

Alexey Tor.

2019-12-08 22:15

reporter   ~0119702

fix3.diff replaces fix2.diff, it supports Brush.Style=bsClear for Ellipse.

fix3.diff (2,360 bytes)
Index: lcl/interfaces/gtk3/gtk3objects.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62357)
+++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
@@ -234,7 +234,7 @@
     procedure drawText(x: Integer; y: Integer; const s: String); overload;
     procedure drawText(x,y,w,h,flags: Integer; const s: String); overload;
     procedure drawLine(x1: Integer; y1: Integer; x2: Integer; y2: Integer);
-    procedure drawEllipse(x: Integer; y: Integer; w: Integer; h: Integer);
+    procedure drawEllipse(x: Integer; y: Integer; w: Integer; h: Integer; AFill: Boolean);
     procedure drawSurface(targetRect: PRect; Surface: Pcairo_surface_t; sourceRect: PRect;
       mask: PGdkPixBuf; maskRect: PRect);
     procedure drawImage(targetRect: PRect; image: PGdkPixBuf; sourceRect: PRect;
@@ -1419,7 +1419,7 @@
 end;
 
 procedure TGtk3DeviceContext.drawEllipse(x: Integer; y: Integer; w: Integer;
-  h: Integer);
+  h: Integer; AFill: Boolean);
 var
   save_matrix:cairo_matrix_t;
 begin
@@ -1438,8 +1438,11 @@
         (*angle2 =*) 2 * Pi
       );
   cairo_close_path(Widget);
-  ApplyBrush;
-  cairo_fill_preserve(Widget);
+  if AFill then
+  begin
+    ApplyBrush;
+    cairo_fill_preserve(Widget);
+  end;
   cairo_restore(Widget);
   ApplyPen;
   cairo_stroke(Widget);
@@ -1585,7 +1588,7 @@
       cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
 
     cairo_close_path(Widget);
-    cairo_fill_preserve(Widget);
+    cairo_fill(Widget);
 
     // now draw the line
     ApplyPen;
@@ -1594,7 +1597,7 @@
     for i := 1 to NumPts-1 do
       cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
     cairo_close_path(Widget);
-    cairo_stroke_preserve(Widget);
+    cairo_stroke(Widget);
   finally
     cairo_restore(Widget);
   end;
Index: lcl/interfaces/gtk3/gtk3winapi.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62357)
+++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
@@ -1053,7 +1053,8 @@
 
 function TGtk3WidgetSet.Ellipse(DC: HDC; x1, y1, x2, y2: Integer): Boolean;
 begin
-  TGtk3DeviceContext(DC).drawEllipse(x1,y1,x2-x1,y2-y1);
+  TGtk3DeviceContext(DC).drawEllipse(x1,y1,x2-x1,y2-y1,
+    TGtk3DeviceContext(DC).CurrentBrush.Style<>BS_NULL);
   Result:=true;
 end;
 
fix3.diff (2,360 bytes)

Alexey Tor.

2019-12-08 22:49

reporter   ~0119703

fix4.diff replaces fix3.diff+fix2.diff, it makes Rects and Ellipse smaller by 1 px at the right side, because right-bottom point must NOT be in the rect/ellipse.

fix4.diff (3,644 bytes)
Index: lcl/interfaces/gtk3/gtk3objects.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62357)
+++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
@@ -234,7 +234,7 @@
     procedure drawText(x: Integer; y: Integer; const s: String); overload;
     procedure drawText(x,y,w,h,flags: Integer; const s: String); overload;
     procedure drawLine(x1: Integer; y1: Integer; x2: Integer; y2: Integer);
-    procedure drawEllipse(x: Integer; y: Integer; w: Integer; h: Integer);
+    procedure drawEllipse(x: Integer; y: Integer; w: Integer; h: Integer; AFill: Boolean);
     procedure drawSurface(targetRect: PRect; Surface: Pcairo_surface_t; sourceRect: PRect;
       mask: PGdkPixBuf; maskRect: PRect);
     procedure drawImage(targetRect: PRect; image: PGdkPixBuf; sourceRect: PRect;
@@ -1330,11 +1330,11 @@
   cairo_save(Widget);
   try
     ApplyPen;
-    cairo_rectangle(Widget, x1, y1, w, h);
+    cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
     cairo_stroke(Widget);
     if AFill then
     begin
-      cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
+      cairo_rectangle(Widget, x1, y1, w - 2, h - 2);
       ApplyBrush;
       cairo_fill(Widget);
     end;
@@ -1419,7 +1419,7 @@
 end;
 
 procedure TGtk3DeviceContext.drawEllipse(x: Integer; y: Integer; w: Integer;
-  h: Integer);
+  h: Integer; AFill: Boolean);
 var
   save_matrix:cairo_matrix_t;
 begin
@@ -1438,8 +1438,11 @@
         (*angle2 =*) 2 * Pi
       );
   cairo_close_path(Widget);
-  ApplyBrush;
-  cairo_fill_preserve(Widget);
+  if AFill then
+  begin
+    ApplyBrush;
+    cairo_fill_preserve(Widget);
+  end;
   cairo_restore(Widget);
   ApplyPen;
   cairo_stroke(Widget);
@@ -1585,7 +1588,7 @@
       cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
 
     cairo_close_path(Widget);
-    cairo_fill_preserve(Widget);
+    cairo_fill(Widget);
 
     // now draw the line
     ApplyPen;
@@ -1594,7 +1597,7 @@
     for i := 1 to NumPts-1 do
       cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
     cairo_close_path(Widget);
-    cairo_stroke_preserve(Widget);
+    cairo_stroke(Widget);
   finally
     cairo_restore(Widget);
   end;
@@ -1677,7 +1680,7 @@
   end;
 
   applyBrush;
-  cairo_rectangle(Widget, x, y, w, h);
+  cairo_rectangle(Widget, x, y, w - 1, h - 1);
   cairo_stroke_preserve(Widget);
   cairo_fill(Widget);
   // cairo_clip(Widget);
Index: lcl/interfaces/gtk3/gtk3winapi.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62357)
+++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
@@ -1053,7 +1053,9 @@
 
 function TGtk3WidgetSet.Ellipse(DC: HDC; x1, y1, x2, y2: Integer): Boolean;
 begin
-  TGtk3DeviceContext(DC).drawEllipse(x1,y1,x2-x1,y2-y1);
+  TGtk3DeviceContext(DC).drawEllipse(
+    x1, y1, x2-x1-1, y2-y1-1,
+    TGtk3DeviceContext(DC).CurrentBrush.Style<>BS_NULL);
   Result:=true;
 end;
 
@@ -1694,8 +1696,7 @@
 
 end;
 
-function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH
-  ): Integer;
+function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH): Integer;
 var
   cr: Pcairo_t;
 begin
@@ -1706,7 +1707,7 @@
   if not IsValidDC(DC) then
     exit;
   cr := TGtk3DeviceContext(DC).Widget;
-  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left, ARect.Bottom-ARect.Top);
+  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
   if IsValidGDIObject(hBr) then
     TGtk3DeviceContext(DC).SetSourceColor(TGtk3Brush(HBR).Color);
   cairo_set_line_width(cr, 1);
fix4.diff (3,644 bytes)

Juha Manninen

2019-12-09 10:01

developer   ~0119704

Oh boy...
Alexey, please take your time to plan and test your changes. You (again) upload here every half-baked experiment you came up with.
Will there be fix5 and fix6 soon?

Alexey Tor.

2019-12-09 10:26

reporter   ~0119705

Juha,
not soon, not in the near 20 hrs.

Zeljan Rikalo

2019-12-09 17:28

developer   ~0119712

With lazarus trunk r62225 fpc-3.0.4 colors were ok here, just updated to current trunk and colors are wrong. So commits to gtk3 ws between 62225 and 62363 aren't correct in case of colors swapping. Tested on Fedora 29 64bit - gtk3-3.24.1 (NOTE THAT IT WORKED OK HERE even with Fedora 24 with older version of gtk3).

Anton Kavalenka

2019-12-09 20:48

reporter   ~0119716

Last edited: 2019-12-09 20:54

View 3 revisions

@Zeljan these commits make PNG with alpha channel painted properly.
See the icons with scissors and folder painted by attached test.

Actual color swapping problem is in gtk3lclintf.inc line 223.
In this place bitmap has to be converted to ARGB32 - this format is default for all canvases created for GUI painting in GTK3 widgetset.
RGB24 canvases would not work with transparent bitmaps.

Juha Manninen

2019-12-10 07:47

developer   ~0119723

@Zeljko, @Anton, the guilty revision is r62310. See the related issue.
Should I revert it or is there a better solution?

Anton Kavalenka

2019-12-10 08:22

reporter   ~0119724

Last edited: 2019-12-10 08:24

View 2 revisions

Pls wait, should be better solution.

Mimicking WinAPI is a pain.

Alexey Tor.

2019-12-10 21:26

reporter   ~0119735

Juha,
fix5.diff replaces fix*.diff, it additionally fixes 2 bugs
- with Rectangle (line had wrong width in Antialiasing mode on)
- with Polygon (was filled even with Brush bsClear)

fix5.diff (6,365 bytes)
Index: lcl/interfaces/gtk3/gtk3objects.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62364)
+++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
@@ -229,12 +229,12 @@
     procedure DeleteObjects;
   public
     procedure drawPoint(x1: Integer; y1: Integer);
-    procedure drawRect(x1: Integer; y1: Integer; w: Integer; h: Integer; const AFill: Boolean);
+    procedure drawRect(x1, y1, w, h: Integer; const AFill: Boolean);
     procedure drawRoundRect(x, y, w, h, rx, ry: Integer);
     procedure drawText(x: Integer; y: Integer; const s: String); overload;
     procedure drawText(x,y,w,h,flags: Integer; const s: String); overload;
     procedure drawLine(x1: Integer; y1: Integer; x2: Integer; y2: Integer);
-    procedure drawEllipse(x: Integer; y: Integer; w: Integer; h: Integer);
+    procedure drawEllipse(x, y, w, h: Integer; AFill: Boolean);
     procedure drawSurface(targetRect: PRect; Surface: Pcairo_surface_t; sourceRect: PRect;
       mask: PGdkPixBuf; maskRect: PRect);
     procedure drawImage(targetRect: PRect; image: PGdkPixBuf; sourceRect: PRect;
@@ -243,7 +243,7 @@
       mask: PGdkPixBuf; maskRect: PRect);
     procedure drawPixmap(p: PPoint; pm: PGdkPixbuf; sr: PRect);
     procedure drawPolyLine(P: PPoint; NumPts: Integer);
-    procedure drawPolygon(P: PPoint; NumPts: Integer; FillRule: integer);
+    procedure drawPolygon(P: PPoint; NumPts: Integer; FillRule: Integer; AFill: Boolean);
     procedure drawPolyBezier(P: PPoint; NumPoints: Integer; Filled, Continuous: boolean);
     procedure EllipseArcPath(CX, CY, RX, RY: Double; Angle1, Angle2: Double; Clockwise, Continuous: Boolean);
     procedure eraseRect(ARect: PRect);
@@ -1324,14 +1324,10 @@
   cairo_stroke(Widget);
 end;
 
-procedure TGtk3DeviceContext.drawRect(x1: Integer; y1: Integer; w: Integer;
-  h: Integer; const AFill: Boolean);
+procedure TGtk3DeviceContext.drawRect(x1, y1, w, h: Integer; const AFill: Boolean);
 begin
   cairo_save(Widget);
   try
-    ApplyPen;
-    cairo_rectangle(Widget, x1, y1, w, h);
-    cairo_stroke(Widget);
     if AFill then
     begin
       cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
@@ -1338,6 +1334,10 @@
       ApplyBrush;
       cairo_fill(Widget);
     end;
+
+    ApplyPen;
+    cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
+    cairo_stroke(Widget);
   finally
     cairo_restore(Widget);
   end;
@@ -1418,8 +1418,7 @@
   cairo_line_to(Widget, x2, y2);
 end;
 
-procedure TGtk3DeviceContext.drawEllipse(x: Integer; y: Integer; w: Integer;
-  h: Integer);
+procedure TGtk3DeviceContext.drawEllipse(x, y, w, h: Integer; AFill: Boolean);
 var
   save_matrix:cairo_matrix_t;
 begin
@@ -1438,8 +1437,11 @@
         (*angle2 =*) 2 * Pi
       );
   cairo_close_path(Widget);
-  ApplyBrush;
-  cairo_fill_preserve(Widget);
+  if AFill then
+  begin
+    ApplyBrush;
+    cairo_fill_preserve(Widget);
+  end;
   cairo_restore(Widget);
   ApplyPen;
   cairo_stroke(Widget);
@@ -1568,7 +1570,7 @@
 end;
 
 procedure TGtk3DeviceContext.drawPolygon(P: PPoint; NumPts: Integer;
-  FillRule: integer);
+  FillRule: Integer; AFill: Boolean);
 var
   i: Integer;
 const
@@ -1576,6 +1578,8 @@
 begin
   cairo_save(Widget);
   try
+   if AFill then
+   begin
     // first apply the fill because the line is drawn over the filled area after
     applyBrush;
     cairo_set_fill_rule(Widget, cairo_fill_rule_t(FillRule));
@@ -1585,9 +1589,9 @@
       cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
 
     cairo_close_path(Widget);
-    cairo_fill_preserve(Widget);
+    cairo_fill(Widget);
+   end;
 
-    // now draw the line
     ApplyPen;
     //cairo_set_antialias(widget, CAIRO_ANTIALIAS_SUBPIXEL);
     cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
@@ -1594,7 +1598,7 @@
     for i := 1 to NumPts-1 do
       cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
     cairo_close_path(Widget);
-    cairo_stroke_preserve(Widget);
+    cairo_stroke(Widget);
   finally
     cairo_restore(Widget);
   end;
@@ -1677,7 +1681,7 @@
   end;
 
   applyBrush;
-  cairo_rectangle(Widget, x, y, w, h);
+  cairo_rectangle(Widget, x, y, w - 1, h - 1);
   cairo_stroke_preserve(Widget);
   cairo_fill(Widget);
   // cairo_clip(Widget);
Index: lcl/interfaces/gtk3/gtk3winapi.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62364)
+++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
@@ -1052,9 +1052,12 @@
 end;
 
 function TGtk3WidgetSet.Ellipse(DC: HDC; x1, y1, x2, y2: Integer): Boolean;
+var
+  bFill: Boolean;
 begin
-  TGtk3DeviceContext(DC).drawEllipse(x1,y1,x2-x1,y2-y1);
-  Result:=true;
+  bFill := TGtk3DeviceContext(DC).CurrentBrush.Style <> BS_NULL;
+  TGtk3DeviceContext(DC).drawEllipse(x1, y1, x2 - x1 - 1, y2 - y1 - 1, bFill);
+  Result := True;
 end;
 
 function TGtk3WidgetSet.EnableScrollBar(Wnd: HWND; wSBflags, wArrows: Cardinal
@@ -1694,8 +1697,7 @@
 
 end;
 
-function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH
-  ): Integer;
+function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH): Integer;
 var
   cr: Pcairo_t;
 begin
@@ -1706,7 +1708,7 @@
   if not IsValidDC(DC) then
     exit;
   cr := TGtk3DeviceContext(DC).Widget;
-  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left, ARect.Bottom-ARect.Top);
+  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
   if IsValidGDIObject(hBr) then
     TGtk3DeviceContext(DC).SetSourceColor(TGtk3Brush(HBR).Color);
   cairo_set_line_width(cr, 1);
@@ -3143,13 +3145,18 @@
 
 function TGtk3WidgetSet.Polygon(DC: HDC; Points: PPoint; NumPts: Integer;
   Winding: boolean): boolean;
+var
+  NFillRule: integer;
+  bFill: boolean;
 begin
   if not IsValidDC(DC) then
     exit(False);
-  if not Winding then // faster
-    TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, ord(CAIRO_FILL_RULE_EVEN_ODD))
+  if Winding then
+    NFillRule := Ord(CAIRO_FILL_RULE_WINDING)
   else
-    TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, Ord(CAIRO_FILL_RULE_WINDING));
+    NFillRule := Ord(CAIRO_FILL_RULE_EVEN_ODD);
+  bFill := TGtk3DeviceContext(DC).CurrentBrush.Style <> BS_NULL;
+  TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, NFillRule, bFill);
   Result:= True;
 end;
 
fix5.diff (6,365 bytes)

Alexey Tor.

2019-12-10 23:14

reporter   ~0119736

Juha,
fix6.diff replaces fix*.diff, fixes additional artifacts (Polygon+Rects with Pen.Style=psClear).

fix6.diff (10,931 bytes)
Index: lcl/interfaces/gtk3/gtk3objects.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3objects.pas	(revision 62364)
+++ lcl/interfaces/gtk3/gtk3objects.pas	(working copy)
@@ -229,12 +229,12 @@
     procedure DeleteObjects;
   public
     procedure drawPoint(x1: Integer; y1: Integer);
-    procedure drawRect(x1: Integer; y1: Integer; w: Integer; h: Integer; const AFill: Boolean);
+    procedure drawRect(x1, y1, w, h: Integer; const AFill, ABorder: Boolean);
     procedure drawRoundRect(x, y, w, h, rx, ry: Integer);
     procedure drawText(x: Integer; y: Integer; const s: String); overload;
     procedure drawText(x,y,w,h,flags: Integer; const s: String); overload;
     procedure drawLine(x1: Integer; y1: Integer; x2: Integer; y2: Integer);
-    procedure drawEllipse(x: Integer; y: Integer; w: Integer; h: Integer);
+    procedure drawEllipse(x, y, w, h: Integer; AFill, ABorder: Boolean);
     procedure drawSurface(targetRect: PRect; Surface: Pcairo_surface_t; sourceRect: PRect;
       mask: PGdkPixBuf; maskRect: PRect);
     procedure drawImage(targetRect: PRect; image: PGdkPixBuf; sourceRect: PRect;
@@ -243,7 +243,8 @@
       mask: PGdkPixBuf; maskRect: PRect);
     procedure drawPixmap(p: PPoint; pm: PGdkPixbuf; sr: PRect);
     procedure drawPolyLine(P: PPoint; NumPts: Integer);
-    procedure drawPolygon(P: PPoint; NumPts: Integer; FillRule: integer);
+    procedure drawPolygon(P: PPoint; NumPts: Integer; FillRule: Integer; AFill,
+      ABorder: Boolean);
     procedure drawPolyBezier(P: PPoint; NumPoints: Integer; Filled, Continuous: boolean);
     procedure EllipseArcPath(CX, CY, RX, RY: Double; Angle1, Angle2: Double; Clockwise, Continuous: Boolean);
     procedure eraseRect(ARect: PRect);
@@ -1324,14 +1325,10 @@
   cairo_stroke(Widget);
 end;
 
-procedure TGtk3DeviceContext.drawRect(x1: Integer; y1: Integer; w: Integer;
-  h: Integer; const AFill: Boolean);
+procedure TGtk3DeviceContext.drawRect(x1, y1, w, h: Integer; const AFill, ABorder: Boolean);
 begin
   cairo_save(Widget);
   try
-    ApplyPen;
-    cairo_rectangle(Widget, x1, y1, w, h);
-    cairo_stroke(Widget);
     if AFill then
     begin
       cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
@@ -1338,6 +1335,12 @@
       ApplyBrush;
       cairo_fill(Widget);
     end;
+    if ABorder then
+    begin
+      ApplyPen;
+      cairo_rectangle(Widget, x1, y1, w - 1, h - 1);
+      cairo_stroke(Widget);
+    end;
   finally
     cairo_restore(Widget);
   end;
@@ -1407,7 +1410,6 @@
   finally
     cairo_restore(Widget);
   end;
-
 end;
 
 procedure TGtk3DeviceContext.drawLine(x1: Integer; y1: Integer; x2: Integer;
@@ -1418,31 +1420,41 @@
   cairo_line_to(Widget, x2, y2);
 end;
 
-procedure TGtk3DeviceContext.drawEllipse(x: Integer; y: Integer; w: Integer;
-  h: Integer);
+procedure TGtk3DeviceContext.drawEllipse(x, y, w, h: Integer; AFill, ABorder: Boolean);
 var
   save_matrix:cairo_matrix_t;
 begin
   cairo_save(Widget);
-  cairo_get_matrix(Widget, @save_matrix);
-  cairo_translate (Widget, x + w / 2.0, y + h / 2.0);
-  cairo_scale (Widget, w / 2.0, h / 2.0);
+  try
+    cairo_get_matrix(Widget, @save_matrix);
+    cairo_translate (Widget, x + w / 2.0, y + h / 2.0);
+    cairo_scale (Widget, w / 2.0, h / 2.0);
+    cairo_new_path(Widget);
+    cairo_arc
+        (
+          (*cr =*) Widget,
+          (*xc =*) 0,
+          (*yc =*) 0,
+          (*radius =*) 1,
+          (*angle1 =*) 0,
+          (*angle2 =*) 2 * Pi
+        );
+    cairo_close_path(Widget);
+    if AFill then
+    begin
+      ApplyBrush;
+      cairo_fill_preserve(Widget);
+    end;
+  finally
+    cairo_restore(Widget);
+  end;
+  if ABorder then
+  begin
+    ApplyPen;
+    cairo_stroke(Widget);
+  end;
+  //if ABorder=false, need to clear current path
   cairo_new_path(Widget);
-  cairo_arc
-      (
-        (*cr =*) Widget,
-        (*xc =*) 0,
-        (*yc =*) 0,
-        (*radius =*) 1,
-        (*angle1 =*) 0,
-        (*angle2 =*) 2 * Pi
-      );
-  cairo_close_path(Widget);
-  ApplyBrush;
-  cairo_fill_preserve(Widget);
-  cairo_restore(Widget);
-  ApplyPen;
-  cairo_stroke(Widget);
 end;
 
 procedure TGtk3DeviceContext.drawSurface(targetRect: PRect;
@@ -1568,7 +1580,7 @@
 end;
 
 procedure TGtk3DeviceContext.drawPolygon(P: PPoint; NumPts: Integer;
-  FillRule: integer);
+  FillRule: Integer; AFill, ABorder: Boolean);
 var
   i: Integer;
 const
@@ -1576,25 +1588,28 @@
 begin
   cairo_save(Widget);
   try
-    // first apply the fill because the line is drawn over the filled area after
-    applyBrush;
-    cairo_set_fill_rule(Widget, cairo_fill_rule_t(FillRule));
-    // + Offset is so the center of the pixel is used.
-    cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
-    for i := 1 to NumPts-1 do
-      cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
+    if AFill then
+    begin
+      // first apply the fill because the line is drawn over the filled area after
+      ApplyBrush;
+      cairo_set_fill_rule(Widget, cairo_fill_rule_t(FillRule));
+      // + Offset is so the center of the pixel is used.
+      cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
+      for i := 1 to NumPts-1 do
+        cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
+      cairo_close_path(Widget);
+      cairo_fill(Widget);
+    end;
 
-    cairo_close_path(Widget);
-    cairo_fill_preserve(Widget);
-
-    // now draw the line
-    ApplyPen;
-    //cairo_set_antialias(widget, CAIRO_ANTIALIAS_SUBPIXEL);
-    cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
-    for i := 1 to NumPts-1 do
-      cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
-    cairo_close_path(Widget);
-    cairo_stroke_preserve(Widget);
+    if ABorder then
+    begin
+      ApplyPen;
+      cairo_move_to(Widget, P[0].X+PixelOffset, P[0].Y+PixelOffset);
+      for i := 1 to NumPts-1 do
+        cairo_line_to(Widget, P[i].X+PixelOffset, P[i].Y+PixelOffset);
+      cairo_close_path(Widget);
+      cairo_stroke(Widget);
+    end;
   finally
     cairo_restore(Widget);
   end;
@@ -1657,10 +1672,9 @@
 
 procedure TGtk3DeviceContext.fillRect(x, y, w, h: Integer; ABrush: HBRUSH);
 var
-  devx, devy, dx, dy, dw, dh: Double;
-  ATarget: Pcairo_surface_t;
-  ANewSurface: Pcairo_surface_t;
-  ACairo: Pcairo_t;
+  //devx, devy, dx, dy, dw, dh: Double;
+  //ATarget: Pcairo_surface_t;
+  //ANewSurface: Pcairo_surface_t;
   ATempBrush: TGtk3Brush;
 begin
   {$ifdef VerboseGtk3DeviceContext}
@@ -1668,24 +1682,24 @@
   {$endif}
 
   cairo_save(Widget);
-  ATempBrush := nil;
-  if ABrush <> 0 then
-  begin
-    ATempBrush := FCurrentBrush;
-    fBkMode:=OPAQUE;
-    SetCurrentBrush(TGtk3Brush(ABrush));
-  end;
+  try
+    ATempBrush := nil;
+    if ABrush <> 0 then
+    begin
+      ATempBrush := FCurrentBrush;
+      fBkMode:=OPAQUE;
+      SetCurrentBrush(TGtk3Brush(ABrush));
+    end;
 
-  applyBrush;
-  cairo_rectangle(Widget, x, y, w, h);
-  cairo_stroke_preserve(Widget);
-  cairo_fill(Widget);
-  // cairo_clip(Widget);
+    applyBrush;
+    cairo_rectangle(Widget, x, y, w - 1, h - 1);
+    cairo_fill(Widget);
 
-  // cairo_fill_preserve(Widget);
-  if ABrush <> 0 then
-    SetCurrentBrush(ATempBrush);
-  cairo_restore(Widget);
+    if ABrush <> 0 then
+      SetCurrentBrush(ATempBrush);
+  finally
+    cairo_restore(Widget);
+  end;
 
   // ATarget := cairo_get_target(Widget);
   (*
Index: lcl/interfaces/gtk3/gtk3widgets.pas
===================================================================
--- lcl/interfaces/gtk3/gtk3widgets.pas	(revision 62364)
+++ lcl/interfaces/gtk3/gtk3widgets.pas	(working copy)
@@ -3079,7 +3079,7 @@
   end;
 
   if BorderStyle <> bsNone then
-    DC.drawRect(0, 0, LCLObject.Width, LCLObject.Height, LCLObject.Color <> clDefault);
+    DC.drawRect(0, 0, LCLObject.Width, LCLObject.Height, LCLObject.Color <> clDefault, True);
 end;
 
 function TGtk3Panel.getText: String;
Index: lcl/interfaces/gtk3/gtk3winapi.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62364)
+++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
@@ -1052,9 +1052,13 @@
 end;
 
 function TGtk3WidgetSet.Ellipse(DC: HDC; x1, y1, x2, y2: Integer): Boolean;
+var
+  bFill, bBorder: Boolean;
 begin
-  TGtk3DeviceContext(DC).drawEllipse(x1,y1,x2-x1,y2-y1);
-  Result:=true;
+  bFill := TGtk3DeviceContext(DC).CurrentBrush.Style <> BS_NULL;
+  bBorder := TGtk3DeviceContext(DC).CurrentPen.Style <> psClear;
+  TGtk3DeviceContext(DC).drawEllipse(x1, y1, x2 - x1 - 1, y2 - y1 - 1, bFill, bBorder);
+  Result := True;
 end;
 
 function TGtk3WidgetSet.EnableScrollBar(Wnd: HWND; wSBflags, wArrows: Cardinal
@@ -1694,8 +1698,7 @@
 
 end;
 
-function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH
-  ): Integer;
+function TGtk3WidgetSet.FrameRect(DC: HDC; const ARect: TRect; hBr: HBRUSH): Integer;
 var
   cr: Pcairo_t;
 begin
@@ -1706,7 +1709,7 @@
   if not IsValidDC(DC) then
     exit;
   cr := TGtk3DeviceContext(DC).Widget;
-  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left, ARect.Bottom-ARect.Top);
+  cairo_rectangle(cr, ARect.Left, ARect.Top, ARect.Right-ARect.Left-1, ARect.Bottom-ARect.Top-1);
   if IsValidGDIObject(hBr) then
     TGtk3DeviceContext(DC).SetSourceColor(TGtk3Brush(HBR).Color);
   cairo_set_line_width(cr, 1);
@@ -3143,13 +3146,19 @@
 
 function TGtk3WidgetSet.Polygon(DC: HDC; Points: PPoint; NumPts: Integer;
   Winding: boolean): boolean;
+var
+  NFillRule: integer;
+  bFill, bBorder: boolean;
 begin
   if not IsValidDC(DC) then
     exit(False);
-  if not Winding then // faster
-    TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, ord(CAIRO_FILL_RULE_EVEN_ODD))
+  if Winding then
+    NFillRule := Ord(CAIRO_FILL_RULE_WINDING)
   else
-    TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, Ord(CAIRO_FILL_RULE_WINDING));
+    NFillRule := Ord(CAIRO_FILL_RULE_EVEN_ODD);
+  bFill := TGtk3DeviceContext(DC).CurrentBrush.Style <> BS_NULL;
+  bBorder := TGtk3DeviceContext(DC).CurrentPen.Style <> psClear;
+  TGtk3DeviceContext(DC).drawPolygon(Points, NumPts, NFillRule, bFill, bBorder);
   Result:= True;
 end;
 
@@ -3257,15 +3266,15 @@
 function TGtk3WidgetSet.Rectangle(DC: HDC; X1, Y1, X2, Y2: Integer): Boolean;
 var
   R: TRect;
+  bFill, bBorder: Boolean;
 begin
   if not IsValidDC(DC) then
     exit(False);
   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,
-      TGtk3DeviceContext(DC).CurrentBrush.Style<>BS_NULL{bsClear}
-      );
+  bFill := TGtk3DeviceContext(DC).CurrentBrush.Style <> BS_NULL;
+  bBorder := TGtk3DeviceContext(DC).CurrentPen.Style <> psClear;
+  TGtk3DeviceContext(DC).drawRect(R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top, bFill, bBorder);
   Result := True;
 end;
 
fix6.diff (10,931 bytes)

Anton Kavalenka

2019-12-11 08:19

reporter   ~0119740

@Juha
In attachment - simple fix, looks crazy but it works.

gtk3winapi.diff (858 bytes)
Index: lcl/interfaces/gtk3/gtk3winapi.inc
===================================================================
--- lcl/interfaces/gtk3/gtk3winapi.inc	(revision 62372)
+++ lcl/interfaces/gtk3/gtk3winapi.inc	(working copy)
@@ -4073,8 +4073,13 @@
   {$ENDIF}
   ATargetRect := Rect(X, Y, Width + X, Height + Y);
   ASrcRect := Rect(XSrc, YSrc, SrcWidth + XSrc, SrcHeight + YSrc);
-  DestContext.drawImage1(@ATargetRect, PgdkPixbuf(SrcContext.CurrentImage.Handle) , @ASrcRect, nil, nil);
-  // Result := True;
+
+  if (DestContext.OwnsSurface) then
+    DestContext.drawImage1(@ATargetRect, PgdkPixbuf(SrcContext.CurrentImage.Handle) , @ASrcRect, nil, nil)
+  else
+    DestContext.drawSurface(@ATargetRect,SrcContext.CairoSurface , @ASrcRect, nil, nil);
+
+  Result := True;
 end;
 
 function TGtk3WidgetSet.SystemParametersInfo(uiAction: DWord; uiParam: DWord;
gtk3winapi.diff (858 bytes)

Anton Kavalenka

2019-12-11 08:20

reporter  

Anton Kavalenka

2019-12-11 08:38

reporter   ~0119742

The idea of fix that current TGtk3DeviceContext.drawSurface does not use Alpha while drawing.
TGtk3DeviceContext.drawImage1 applies alpha but does not care if it is cairo image in ARGB32 or it is LCL-prepared BGRA32

So if we are painting to bitmap - we use alpha-enabled drawing, if we are painting to widget-attached surface - we are using straight copy.

Juha Manninen

2019-12-11 12:35

developer   ~0119745

Thanks Anton. The patch seems to fix the colors. Applied in r62377.

Alexey Tor.

2019-12-11 12:47

reporter   ~0119747

Pls apply my fix as well, we need to continue to see more places.

Issue History

Date Modified Username Field Change
2019-11-28 20:24 Alexey Tor. New Issue
2019-11-28 20:24 Alexey Tor. File Added: gtk2.png
2019-11-28 20:24 Alexey Tor. File Added: gtk3.png
2019-11-28 20:24 Alexey Tor. File Added: tst-gtk3-artifacts.zip
2019-12-07 10:36 Anton Kavalenka File Added: gtk3objects.diff
2019-12-07 10:36 Anton Kavalenka File Added: gtk3winapi.inc.diff
2019-12-07 10:36 Anton Kavalenka Note Added: 0119673
2019-12-07 12:16 Juha Manninen Note Added: 0119678
2019-12-07 12:16 Juha Manninen Note Edited: 0119678 View Revisions
2019-12-07 12:38 Juha Manninen Note Edited: 0119678 View Revisions
2019-12-07 12:51 Juha Manninen Note Added: 0119679
2019-12-07 13:34 Anton Kavalenka Note Added: 0119680
2019-12-07 15:32 Alexey Tor. Note Added: 0119681
2019-12-07 15:42 Juha Manninen Note Added: 0119682
2019-12-07 19:14 Anton Kavalenka Note Added: 0119684
2019-12-07 19:34 Anton Kavalenka File Added: test1.bmp
2019-12-07 19:34 Anton Kavalenka Note Added: 0119685
2019-12-07 21:47 Juha Manninen Note Added: 0119686
2019-12-08 14:42 Alexey Tor. File Added: fix1.diff
2019-12-08 14:42 Alexey Tor. Note Added: 0119694
2019-12-08 14:50 Alexey Tor. File Added: tst-gtk3-artifacts-2.zip
2019-12-08 14:50 Alexey Tor. Note Added: 0119695
2019-12-08 16:45 Juha Manninen File Added: GTK3_artifact.png
2019-12-08 16:45 Juha Manninen Note Added: 0119696
2019-12-08 20:48 Juha Manninen Note Edited: 0119696 View Revisions
2019-12-08 20:50 Juha Manninen Fixed in Revision => r62356
2019-12-08 20:50 Juha Manninen LazTarget => -
2019-12-08 20:50 Juha Manninen Widgetset GTK 3 => GTK 3
2019-12-08 21:28 Alexey Tor. File Added: fix2.diff
2019-12-08 21:28 Alexey Tor. Note Added: 0119701
2019-12-08 22:15 Alexey Tor. File Added: fix3.diff
2019-12-08 22:15 Alexey Tor. Note Added: 0119702
2019-12-08 22:49 Alexey Tor. File Added: fix4.diff
2019-12-08 22:49 Alexey Tor. Note Added: 0119703
2019-12-09 10:01 Juha Manninen Note Added: 0119704
2019-12-09 10:26 Alexey Tor. Note Added: 0119705
2019-12-09 17:28 Zeljan Rikalo Note Added: 0119712
2019-12-09 20:48 Anton Kavalenka Note Added: 0119716
2019-12-09 20:48 Anton Kavalenka Note Edited: 0119716 View Revisions
2019-12-09 20:54 Anton Kavalenka Note Edited: 0119716 View Revisions
2019-12-10 07:32 Juha Manninen Relationship added related to 0036254
2019-12-10 07:47 Juha Manninen Note Added: 0119723
2019-12-10 08:22 Anton Kavalenka Note Added: 0119724
2019-12-10 08:24 Anton Kavalenka Note Edited: 0119724 View Revisions
2019-12-10 21:26 Alexey Tor. File Added: fix5.diff
2019-12-10 21:26 Alexey Tor. Note Added: 0119735
2019-12-10 23:14 Alexey Tor. File Added: fix6.diff
2019-12-10 23:14 Alexey Tor. Note Added: 0119736
2019-12-11 08:19 Anton Kavalenka File Added: gtk3winapi.diff
2019-12-11 08:19 Anton Kavalenka Note Added: 0119740
2019-12-11 08:20 Anton Kavalenka File Added: Здымак экрана, 2019-12-11 10-20-11.png
2019-12-11 08:38 Anton Kavalenka Note Added: 0119742
2019-12-11 12:35 Juha Manninen Fixed in Revision r62356 => r62356, r62377
2019-12-11 12:35 Juha Manninen Widgetset GTK 3 => GTK 3
2019-12-11 12:35 Juha Manninen Note Added: 0119745
2019-12-11 12:47 Alexey Tor. Note Added: 0119747