Skip to content

Commit

Permalink
use more efficient signal_connect in GtkCanvas, add to tests (#41)
Browse files Browse the repository at this point in the history
We were using the more user friendly `signal_connect` with callbacks that were defined for each Canvas. This should be more efficient and it lets the GtkCanvas be GC'ed when destroyed.
  • Loading branch information
jwahlstrand authored Sep 24, 2023
1 parent d51ff5e commit d8c7868
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 39 deletions.
62 changes: 31 additions & 31 deletions src/cairo.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import Cairo: CairoSurface, CairoContext, CairoARGBSurface

using Cairo_jll

function canvas_draw_backing_store(w, cr, width, height, user_data) # cr is a Cairo context, user_data is a Cairo surface
function _canvas_draw_backing_store(w, cr, width, height, user_data) # cr is a Cairo context, user_data is a Cairo surface
user_data==C_NULL && return

ccall((:cairo_set_source_surface, libcairo), Nothing,
(Ptr{Nothing}, Ptr{Nothing}, Float64, Float64), cr, user_data, 0, 0)
(Ptr{Nothing}, Ptr{Nothing}, Float64, Float64), cr, user_data, 0, 0)
ccall((:cairo_paint, libcairo), Nothing, (Ptr{Nothing},), cr)
end

Expand All @@ -15,6 +15,30 @@ function _init_canvas!(widget, w, h)
widget.backcc = CairoContext(widget.back)
end

function _canvas_on_realize(::Ptr, canvas)
if canvas.is_sized
_canvas_on_resize(da,1,1)
end
nothing
end

function _canvas_on_resize(::Ptr, width, height, canvas)
canvas.is_sized = true
if G_.get_realized(canvas)
_init_canvas!(canvas, width, height)

if isa(canvas.resize, Function)
canvas.resize(canvas)
end

draw_back = @cfunction(_canvas_draw_backing_store, Nothing, (Ptr{GObject}, Ptr{Nothing}, Cint, Cint, Ptr{Nothing}))
ccall((:gtk_drawing_area_set_draw_func, libgtk4), Nothing, (Ptr{GObject}, Ptr{Nothing}, Ptr{Nothing}, Ptr{Nothing}), getfield(canvas,:handle), draw_back, canvas.back.ptr, C_NULL)

draw(canvas)
end
nothing
end

"""
GtkCanvas(w = -1, h = -1, init_back = false; kwargs...)
Expand Down Expand Up @@ -47,35 +71,11 @@ mutable struct GtkCanvas <: GtkDrawingArea # NOT a GType
_init_canvas!(widget, w, h)
end

function on_realize(da::GtkWidget)
if widget.is_sized
on_resize(da,1,1)
end
nothing
end

on_resize(da::GtkDrawingArea, width, height) = on_resize(da, Cint(width), Cint(height))
function on_resize(da::GtkDrawingArea, width::Cint, height::Cint)
widget.is_sized = true
if G_.get_realized(widget)
_init_canvas!(widget, width, height)

if isa(widget.resize, Function)
widget.resize(widget)
end

draw_back = @cfunction(canvas_draw_backing_store, Nothing, (Ptr{GObject}, Ptr{Nothing}, Cint, Cint, Ptr{Nothing}))
ccall((:gtk_drawing_area_set_draw_func, libgtk4), Nothing, (Ptr{GObject}, Ptr{Nothing}, Ptr{Nothing}, Ptr{Nothing}), getfield(da,:handle), draw_back, widget.back.ptr, C_NULL)

draw(widget)
end
nothing
end

signal_connect(Base.inferencebarrier(on_realize), widget, "realize")
signal_connect(Base.inferencebarrier(on_resize), widget, "resize")
widget = GLib.gobject_move_ref(widget, da)
signal_connect(Base.inferencebarrier(_canvas_on_realize), widget, "realize", Nothing, (), false, widget)
signal_connect(Base.inferencebarrier(_canvas_on_resize), widget, "resize", Nothing, (Cint, Cint), false, widget)

return GLib.gobject_move_ref(widget, da)
return widget
end
end
const GtkCanvasLeaf = GtkCanvas
Expand Down
29 changes: 21 additions & 8 deletions test/gui/canvas.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Test, Gtk4, Cairo

@testset "Canvas & AspectFrame" begin
c = GtkCanvas()
c = GtkCanvas(100,100)
f = GtkAspectFrame(0.5, 1, 0.5, false)
f[] = c
@test f[] == c
Expand All @@ -14,26 +14,31 @@ ggz = GtkGestureZoom(c)
t = Gtk4.find_controller(c,GtkEventControllerMotion)
@test t==gm
@test widget(gm) == c
drew = Ref(false)
resized = Ref(false)
c.draw = function(_)
if isdefined(c,:back)
ctx = Gtk4.getgc(c)
set_source_rgb(ctx, 1.0, 0.0, 0.0)
paint(ctx)
drew[] = true
end
end
gf = GtkEventControllerFocus(c)
w = GtkWindow(f, "Canvas")
draw(c)
sleep(0.5)
reveal(c)
destroyed = Ref(false)
function test_destroy(w)
destroyed[] = true
@test drew[]
drew[]=false
resize(c) do _
resized[] = true
end
on_signal_destroy(test_destroy, c)
Gtk4.G_.set_content_width(c,200)
sleep(0.1)
@test resized[]
@test drew[]
reveal(c)
destroy(w)
#sleep(0.5)
#@test destroyed[] == true
end

@testset "SetCoordinates" begin
Expand Down Expand Up @@ -72,3 +77,11 @@ w = GtkWindow(nb,"TestDataViewer",600,600)
@test pagenumber(nb,c)==3
destroy(w)
end

@testset "Canvas initialization" begin
# must provide a nonzero size to use `init_back`
@test_throws ErrorException c = GtkCanvas(0,0,true)
c = GtkCanvas(10,10,true)
@test isdefined(c,:back)
end

0 comments on commit d8c7868

Please sign in to comment.