Skip to content

Commit

Permalink
In callbacks, convert inputs and outputs between pointers and objects (
Browse files Browse the repository at this point in the history
…#45)

In callbacks we have had to convert pointer arguments to GObjects and return pointers rather than the GObjects. This modifies the GI-generated callback functions to do that automatically, which makes the user-supplied callbacks shorter and cleaner. This also automatically adds a reference to GObject pointers on the output where appropriate.

Also adds some crude documentation for GtkListView, GtkColumnView, GtkCustomFilter, and GtkCustomSorter and miscellaneous other fixes.
  • Loading branch information
jwahlstrand authored Nov 12, 2023
1 parent 09682e4 commit 043eb29
Show file tree
Hide file tree
Showing 39 changed files with 1,014 additions and 192 deletions.
63 changes: 47 additions & 16 deletions GI/src/giimport.jl
Original file line number Diff line number Diff line change
Expand Up @@ -414,19 +414,40 @@ function decl(callbackinfo::GICallbackInfo)
args=get_args(callbackinfo)
rettypeinfo=get_return_type(callbackinfo)
rettype = extract_type(rettypeinfo)
retexpr = (rettype.ctype == :Nothing) ? :(nothing) : :(convert($(rettype.ctype), ret))
retexpr = if rettype.ctype == :(Ptr{GObject}) || rettype.ctype == :(Ptr{GVariant}) # not a general solution, but there is not a huge variety of output types
if get_caller_owns(callbackinfo) == GITransfer.EVERYTHING
:(ret != C_NULL && GLib.glib_ref(ret);convert($(rettype.ctype),GLib.get_pointer(ret)))
else
:(convert($(rettype.ctype),GLib.get_pointer(ret)))
end
elseif rettype.ctype == :Nothing
:(nothing)
else
:(convert($(rettype.ctype), ret))
end

closure = get_closure(callbackinfo)
for arg in args
push!(fargs, get_name(arg))
end
if closure == -1
throw(NotImplementedError("Not implementing callback $name, didn't find a closure"))
else
closure_name = get_name(args[closure+1])
end

input_conversion=[]
for arg in args
argname = get_name(arg)
push!(fargs, argname)
if argname != closure_name
typ = extract_type(arg)
expr = convert_from_c(argname,arg,typ)
if expr!==nothing
push!(input_conversion,:($argname = $expr))
end
end
end
d = quote
function $name($(fargs...))
$(input_conversion...)
f = $closure_name
ret = f($(fargs[1:end-1]...))
$retexpr
Expand Down Expand Up @@ -503,6 +524,7 @@ function extract_type(info::GIArgInfo)
if may_be_null(info) && typdesc.jtype !== :Any
jtype=typdesc.jtype
typdesc.jtype = :(Maybe($jtype))
typdesc.jstype = :($jtype)
end
typdesc
end
Expand Down Expand Up @@ -637,7 +659,7 @@ function convert_from_c(name::Symbol, arginfo::ArgInfo, typeinfo::TypeDesc{T}) w
end

owns = typeof(arginfo)==GIFunctionInfo ? get_caller_owns(arginfo) : get_ownership_transfer(arginfo)
if owns==GITransfer.EVERYTHING # means it's our responsibility to free both the array and its contents
if owns == GITransfer.EVERYTHING # means it's our responsibility to free both the array and its contents
if is_zero_terminated(argtypeinfo)
if elmctype == :(Ptr{UInt8}) || elmctype == :(Cstring)
return :(_len=length_zt($name);arrtemp=bytestring.(unsafe_wrap(Vector{$elmctype}, $name,_len));GLib.g_strfreev($name);arrtemp)
Expand All @@ -653,19 +675,25 @@ function convert_from_c(name::Symbol, arginfo::ArgInfo, typeinfo::TypeDesc{T}) w
return :(arrtemp=copy(unsafe_wrap(Vector{$elmctype}, $name, $lensymb[]));GLib.g_free($name);arrtemp)
end
else
error("No way to find the length of the output array")
throw(NotImplementedError("No way to find the length of the output array"))
end
end
elseif owns==GITransfer.CONTAINER && lensymb !== nothing # we need to free the array but not the contents
if elmtype.gitype == GObject
return :(arrtemp=collect(unsafe_wrap(Vector{$elmctype}, $name,$lensymb[]));GLib.g_free($name);arrtemp=convert.($(elmtype.jtype), arrtemp, false))
elseif elmctype == :(Ptr{UInt8}) || elmctype == :(Cstring)
return :(bytestring.(unsafe_wrap(Vector{$elmctype}, $name, $lensymb[]),true))
elseif owns == GITransfer.CONTAINER # we need to free the array but not the contents
if lensymb !== nothing
if elmtype.gitype == GObject
return :(arrtemp=collect(unsafe_wrap(Vector{$elmctype}, $name,$lensymb[]));GLib.g_free($name);arrtemp=convert.($(elmtype.jtype), arrtemp, false))
elseif elmctype == :(Ptr{UInt8}) || elmctype == :(Cstring)
return :(bytestring.(unsafe_wrap(Vector{$elmctype}, $name, $lensymb[]),true))
else
return :(arrtemp=collect(unsafe_wrap(Vector{$elmctype}, $name,$lensymb[]));GLib.g_free($name);arrtemp)
end
elseif is_zero_terminated(argtypeinfo)
throw(NotImplementedError("Zero terminated array, transfer container"))
else
return :(arrtemp=collect(unsafe_wrap(Vector{$elmctype}, $name,$lensymb[]));GLib.g_free($name);arrtemp)
throw(NotImplementedError("Transfer container, no length argument"))
end
elseif owns == GITransfer.NOTHING
if lensymb !== nothing # we don't need to free anything (but should we make a copy?)
elseif owns == GITransfer.NOTHING # we don't need to free anything (but should we make a copy?)
if lensymb !== nothing
if elmctype == :(Ptr{UInt8}) || elmctype == :(Cstring)
return :(bytestring.(unsafe_wrap(Vector{$elmctype}, $name, $lensymb[])))
elseif elmtype.gitype == GObject
Expand All @@ -678,8 +706,11 @@ function convert_from_c(name::Symbol, arginfo::ArgInfo, typeinfo::TypeDesc{T}) w
return :(_len=length_zt($name);arrtemp=bytestring.(unsafe_wrap(Vector{$elmctype}, $name,_len));arrtemp)
end
throw(NotImplementedError("Zero terminated array that's not strings"))
else # do nothing here
return nothing
end
end
println("$owns")
throw(NotImplementedError("Unknown array type"))
end

Expand Down Expand Up @@ -884,7 +915,7 @@ function convert_from_c(name::Symbol, arginfo::ArgInfo, typeinfo::TypeDesc{T}, i
owns = get_ownership_transfer(arginfo) != GITransfer.NOTHING
object = get_container(arginfo)
if may_be_null(arginfo)
:(convert_if_not_null($(typeinfo.jtype), $name, $owns))
:(convert_if_not_null($(typeinfo.jstype), $name, $owns))
elseif isconstructor && !get_abstract(object)
# For a constructor, we know this is a never-before-seen object, so use the known concrete type to allow type inference
# Many of these have an abstract type as the return type in GI, but we need the
Expand All @@ -911,7 +942,7 @@ function convert_from_c(name::Symbol, arginfo::ArgInfo, typeinfo::TypeDesc{T}) w
typ = isa(arginfo, GIFunctionInfo) ? 0 : get_type(arginfo)

if may_be_null(arginfo)
:(convert_if_not_null($(typeinfo.jtype), $name, $owns))
:(convert_if_not_null($(typeinfo.jstype), $name, $owns))
elseif typ == 0 || (typ != 0 && is_pointer(typ))
:(convert($(typeinfo.jtype), $name, $owns))
end
Expand Down
8 changes: 6 additions & 2 deletions docs/src/doc/GLib_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Gtk4.GLib.g_source_remove
Gtk4.GLib.get_uv_loop_integration
Gtk4.GLib.set_uv_loop_integration
Gtk4.GLib.is_uv_loop_integration_enabled
Gtk4.GLib.run
```

## REPL helper functions
Expand All @@ -35,18 +36,21 @@ Gtk4.GLib.signal_argument_types
Gtk4.GLib.on_notify
Gtk4.GLib.bind_property
Gtk4.GLib.unbind_property
Gtk4.GLib.setproperties!
```

## Signals
```@docs
Gtk4.GLib.signal_handler_is_connected
Gtk4.GLib.signal_handler_disconnect
Gtk4.GLib.signal_handler_block
Gtk4.GLib.signal_handler_unblock
Gtk4.GLib.waitforsignal
```

## Miscellaneous
## GObject type system
```@docs
Gtk4.GLib.g_type
Gtk4.GLib.run
Gtk4.GLib.find_leaf_type
```

8 changes: 7 additions & 1 deletion docs/src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ Gtk4.present
Gtk4.toplevels
```

## Input widgets

```@docs
Gtk4.configure!
```

## Dialogs
```@docs
Gtk4.ask_dialog
Expand All @@ -46,7 +52,7 @@ Gtk4.open_dialog
Gtk4.save_dialog
```

## GtkCanvas (drawing with Cairo)
## GtkCanvas (for Cairo drawing)

```@docs
Gtk4.GtkCanvas
Expand Down
7 changes: 3 additions & 4 deletions docs/src/manual/canvas.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Drawing with Cairo

!!! note "Example"
The code on this page can be found in "canvas.jl" in the ["examples" subdirectory](https://github.com/JuliaGtk/Gtk4.jl/tree/main/examples).
The code below can be found in "canvas.jl" in the ["examples" subdirectory](https://github.com/JuliaGtk/Gtk4.jl/tree/main/examples).

Cairo based drawing can be done on Gtk4.jl's `GtkCanvas` widget, which is based on GTK's `GtkDrawingArea`. The canvas widget comes with a backing store (a Cairo image surface). You control what is drawn on this backing store by defining a `draw` function:

Expand Down Expand Up @@ -54,7 +54,6 @@ function on_pressed(controller, n_press, x, y)
end

signal_connect(on_pressed, g, "pressed")

```

This will draw a green circle on the canvas at every mouse click.
Expand Down Expand Up @@ -94,5 +93,5 @@ w = GtkWindow(canvas,"CairoMakie example")
end
```

A more complicated example can be found in the ["examples" subdirectory](https://github.com/JuliaGtk/Gtk4.jl/tree/main/examples).
For interactive plots, you can try [Gtk4Makie.jl](https://github.com/JuliaGtk/Gtk4Makie.jl), which draws GLMakie plots onto GTK's `GtkGLArea` widget.
!!! note "Example"
A more complicated example can be found in "canvas_cairomakie.jl" in the ["examples" subdirectory](https://github.com/JuliaGtk/Gtk4.jl/tree/main/examples).
Loading

0 comments on commit 043eb29

Please sign in to comment.