Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In callbacks, convert inputs and outputs between pointers and objects #45

Merged
merged 7 commits into from
Nov 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading