Gtk3: fixed TGtk3DeviceContext.GetPixel() so it works on wayland too. Patch by Anton Kavalenka. issue #41413

This commit is contained in:
zeljan1 2025-02-10 19:59:52 +01:00
parent dfb0c3bf81
commit 32c1370c50

View File

@ -2006,88 +2006,57 @@ function TGtk3DeviceContext.getPixel(x, y: Integer): TColor;
var
APixbuf: PGdkPixbuf;
AData: PByte;
APixelValue: LongWord;
APixelValue: Longword;
ASurfaceWidth, ASurfaceHeight, ARowStride: Integer;
AOutSize: Tcairo_rectangle_int_t;
ARegion: Pcairo_region_t;
pixels,row: pointer;
stride,r,c:integer;
st:Tcairo_surface_type_t;
cr:Pcairo_t;
img_surf,view:Pcairo_surface_t;
begin
Result := 0;
if CairoSurface = nil then
exit;
if cairo_surface_get_type(CairoSurface) = CAIRO_SURFACE_TYPE_IMAGE then
cairo_surface_flush(CairoSurface);
st := cairo_surface_get_type(CairoSurface);
if st in [CAIRO_SURFACE_TYPE_XLIB, CAIRO_SURFACE_TYPE_XCB] then
begin
ASurfaceWidth := cairo_image_surface_get_width(CairoSurface);
ASurfaceHeight := cairo_image_surface_get_height(CairoSurface);
(* Allocate an image surface of a suitable size *)
view:=cairo_surface_create_for_rectangle(CairoSurface,fncOrigin.X + x -PixelOffset, fncOrigin.Y + y - PixelOffset,1 + PixelOffset, 1 + PixelOffset);
img_surf := cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
cr := cairo_create(img_surf);
cairo_set_source_surface(cr, view, 0, 0);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_paint(cr);
cairo_surface_flush (img_surf);
// cairo_surface_write_to_png(img_surf, 'image.png');
cairo_destroy(cr);
pixels := cairo_image_surface_get_data(img_surf);
APixelValue:=PLongInt(pixels)^;
cairo_surface_destroy(img_surf);
cairo_surface_destroy(view);
end else
if st=CAIRO_SURFACE_TYPE_IMAGE then
begin
ASurfaceWidth := 0;
ASurfaceHeight := 0;
//Our context have or GtkWidget or GdkWindow available.
if Assigned(Self.Parent) then
pixels := cairo_image_surface_get_data(CAirosurface);
if Assigned(pixels) then
begin
ASurfaceWidth := gtk_widget_get_allocated_width(Self.Parent);
ASurfaceHeight := gtk_widget_get_allocated_height(Self.Parent);
end else
if Assigned(Self.Window) then
begin
//for now we'll use cairo region, it's faster than
//calculate client size by calling gdk_window_get_geometry() + gdk_window_get_frame_extents()
ARegion := gdk_window_get_clip_region(Self.Window);
if ARegion <> nil then
begin
cairo_region_get_extents(ARegion, @AOutSize);
ASurfaceWidth := AOutSize.width;
ASurfaceHeight := AOutSize.height;
cairo_region_destroy(ARegion);
end;
stride := cairo_image_surface_get_stride(CairoSurface);
row:=pixels+(fncOrigin.Y+Y)*stride;
inc(row,(fncOrigin.X+X)*sizeof(longint));
APixelValue:=PLongInt(row)^;
end;
end;
if (X < 0) or (Y < 0) or (X >= ASurfaceWidth) or (Y >= ASurfaceHeight) then
begin
DebugLn(Format('ERROR: TGtk3DeviceContext.getPixel: Pixel out of bounds x %d y %d surface width %d height %d !',
[x, y, ASurfaceWidth, ASurfaceHeight]));
Exit;
end;
if cairo_surface_get_type(CairoSurface) = CAIRO_SURFACE_TYPE_IMAGE then
begin
cairo_surface_flush(CairoSurface);
AData := PByte(cairo_image_surface_get_data(CairoSurface));
if AData <> nil then
begin
ARowStride := cairo_image_surface_get_stride(CairoSurface);
APixelValue := PLongWord(AData + (Y * ARowStride) + (X * 4))^;
Result := ((APixelValue and $00FF0000) shr 16) or
(APixelValue and $0000FF00) or
((APixelValue and $000000FF) shl 16);
exit;
end else
begin
DebugLn('Error: GetPixel for CAIRO_SURFACE_TYPE_IMAGE failed.');
exit(0);
end;
end;
APixbuf := gdk_pixbuf_get_from_surface(CairoSurface, X, Y, 1, 1);
if APixbuf = nil then
Exit;
AData := gdk_pixbuf_get_pixels(APixbuf);
ARowStride := gdk_pixbuf_get_rowstride(APixbuf);
APixelValue := PLongWord(AData)^;
Result := ((APixelValue and $FF0000) shr 16) or
(APixelValue and $00FF00) or
((APixelValue and $0000FF) shl 16);
(APixelValue and $00FF00) or
((APixelValue and $0000FF) shl 16);
g_object_unref(APixbuf);
end;