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

export some interface methods using GI, define GErrorException #46

Merged
merged 5 commits into from
Nov 25, 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
12 changes: 11 additions & 1 deletion GI/src/giexport.jl
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ function all_objects!(exprs,exports,ns;print_summary=true,handled=Symbol[],skipl
loaded
end

function all_object_methods!(exprs,ns;skiplist=Symbol[],object_skiplist=Symbol[], liboverride=nothing, exclude_deprecated=true)
function all_object_methods!(exprs,ns;skiplist=Symbol[],object_skiplist=Symbol[], liboverride=nothing, exclude_deprecated=true, interface_helpers=true)
not_implemented=0
skipped=0
created=0
Expand Down Expand Up @@ -311,6 +311,16 @@ function all_object_methods!(exprs,ns;skiplist=Symbol[],object_skiplist=Symbol[]
end
end
end
if interface_helpers
for i in get_interfaces(o)
printstyled("$(get_name(i))\n"; color=:blue)
for m in get_methods(i)
printstyled("$(get_name(m))\n"; color=:green)
fun = create_interface_method(m, o, liboverride)
fun !== nothing && push!(exprs, fun)
end
end
end
end
end

Expand Down
72 changes: 47 additions & 25 deletions GI/src/giimport.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1086,6 +1086,20 @@ function get_constructors(info::Union{GIStructInfo,GIObjectInfo};skiplist=Symbol
outs
end

function get_closure_args(info::GIFunctionInfo)
closure_args=Dict{Symbol,Int}()
for arg in get_args(info)
is_skip(arg) && continue
typ = extract_type(arg)
closure = get_closure(arg)
if typ.gitype == Function && closure > -1
aname = Symbol("_", get_name(arg))
closure_args[aname]=closure+1
end
end
closure_args
end

function get_jargs(info::GIFunctionInfo)
flags = get_flags(info)
args = get_args(info)
Expand All @@ -1097,13 +1111,15 @@ function get_jargs(info::GIFunctionInfo)
push!(jargs, Arg(:instance, typeinfo.jtype))
end
end
for arg in args
# go through args and find the closure arguments for each function argument
closure_args=get_closure_args(info)
for (iarg,arg) in enumerate(args)
is_skip(arg) && continue
aname = Symbol("_$(get_name(arg))")
typ = extract_type(arg)
dir = get_direction(arg)
if dir != GIDirection.OUT
push!(jargs, Arg( aname, typ.jtype))
!(iarg in values(closure_args)) && push!(jargs, Arg( aname, typ.jtype))
end
end

Expand All @@ -1127,6 +1143,32 @@ function constructor_name(info, mname)
object !== nothing ? Symbol("$(get_name(object))_$mname") : mname
end

function create_interface_method(info::GIFunctionInfo, obj::GIObjectInfo, liboverride = nothing)
name = get_name(info)
flags = get_flags(info)
if flags & GIFunction.IS_METHOD == 0
return nothing
end
ms = get_methods(obj)
if findfirst(m->get_name(m)==name, ms) !== nothing # there is a conflicting object method
return nothing
end
jargs = get_jargs(info)
jargsp = copy(jargs)
typeinfo = extract_type(InstanceType,obj)
# replace the first argument of the definition with our object
jargsp[1] = Arg(:instance, typeinfo.jtype)
# replace the first argument of the call
callargs = Any[n for n in names(jargs)]
ifacename = get_full_name(get_container(info))
callargs[1] = :($ifacename($(callargs[1])))
j_call = Expr(:call, name, jparams(jargsp)... )
blk = quote
$name($(callargs...))
end
Expr(:function, j_call, blk)
end

# with some partial-evaluation half-magic
# (or maybe just jit-compile-time macros)
# this could be simplified significantly
Expand All @@ -1138,12 +1180,11 @@ function create_method(info::GIFunctionInfo, liboverride = nothing)
epilogue = Any[]
retvals = Symbol[]
cargs = Arg[]
jargs = Arg[]
jargs = get_jargs(info)
if flags & GIFunction.IS_METHOD != 0
object = get_container(info)
if object !== nothing
typeinfo = extract_type(InstanceType,object)
push!(jargs, Arg(:instance, typeinfo.jtype))
push!(cargs, Arg(:instance, typeinfo.ctype))
end
end
Expand All @@ -1166,24 +1207,14 @@ function create_method(info::GIFunctionInfo, liboverride = nothing)
end
end
# go through args and find the closure arguments for each function argument
closure_args=Dict{Symbol,Int}()
for arg in args
is_skip(arg) && continue
typ = extract_type(arg)
closure = get_closure(arg)
if typ.gitype == Function && closure > -1
aname = Symbol("_", get_name(arg))
closure_args[aname]=closure+1
end
end
closure_args=get_closure_args(info)
for (iarg,arg) in enumerate(args)
is_skip(arg) && continue
aname = Symbol("_$(get_name(arg))")
typ = extract_type(arg)
dir = get_direction(arg)
anametran = aname
if dir != GIDirection.OUT
!(iarg in values(closure_args)) && push!(jargs, Arg( aname, typ.jtype))
anametran, expr = convert_to_c(aname,arg,typ)
if expr !== nothing && !(iarg in values(closure_args))
if typ.gitype == Function
Expand Down Expand Up @@ -1232,22 +1263,13 @@ function create_method(info::GIFunctionInfo, liboverride = nothing)
arrlen=get_array_length(typeinfo)
if typ.gitype == GICArray && arrlen >= 0
len_name=Symbol("_",get_name(args[arrlen+1]))
len_i=findfirst(a->(a.name === len_name),jargs)
len_i=findfirst(a->((Symbol("_$(get_name(a))") === len_name && get_direction(a) != GIDirection.OUT)),args)
if len_i !== nothing
deleteat!(jargs,len_i)
push!(prologue, :($len_name = length($aname)))
end
len_i=findfirst(==(len_name),retvals)
len_i !== nothing && deleteat!(retvals,len_i)
end
closure = get_closure(arg)
if typ.gitype == Function && closure > -1
closure_name=Symbol("_",get_name(args[closure+1]))
closure_i=findfirst(a->(a.name === closure_name),jargs)
if closure_i !== nothing
deleteat!(jargs,closure_i) # could avoid this by using ignore_args to skip adding them to jargs
end
end
end
if rettype.gitype == GICArray
arrlen=get_array_length(rettypeinfo)
Expand Down
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "Gtk4"
uuid = "9db2cae5-386f-4011-9d63-a5602296539b"
version = "0.5.4"
version = "0.6.0"

[deps]
BitFlags = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35"
Expand Down Expand Up @@ -35,6 +35,7 @@ Glib_jll = "2.74.0"
Graphene_jll = "1.10"
Graphics = "1"
JLLWrappers = "1.4.0"
Libdl = "1.6"
Librsvg_jll = "2.54"
Pango_jll = "1.50"
Preferences = "1"
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ For auto-generated code, Gtk4.jl relies on GObject introspection data generated

Note that this package uses binaries for the GTK library and its dependencies that are built and packaged using [BinaryBuilder.jl](https://github.com/JuliaPackaging/BinaryBuilder.jl). On Linux it does **not** use the binaries that are packaged with your distribution. The build scripts for the binaries used by Gtk4.jl, including the library versions currently being used, can be found by perusing [Yggdrasil.jl](https://github.com/JuliaPackaging/Yggdrasil.jl).

### Known incompatibilities

Gtk4.jl interferes with some other packages, including [PyPlot.jl](https://github.com/JuliaPy/PyPlot.jl) and [GLMakie.jl](https://github.com/MakieOrg/Makie.jl). To use Gtk4 based packages with Makie, you can use [Gtk4Makie.jl](https://github.com/JuliaGtk/Gtk4Makie.jl).

## Enabling GTK4's EGL backend (Linux)
On Wayland, a Cairo-based fallback backend will be used unless you tell `libglvnd_jll` where to find libEGL. This can be done by setting the environment variable __EGL_VENDOR_LIBRARY_DIRS. See [here](https://gitlab.freedesktop.org/glvnd/libglvnd/-/blob/master/src/EGL/icd_enumeration.md) for details.

Expand Down
4 changes: 2 additions & 2 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
- `dialogs.jl` demonstrates various types of dialogs.

## Drawing
- `canvas.jl` demonstrates use of `GtkCanvas`, which allows drawing with Cairo. Also shows how to change the cursor when it's over a certain widget.
- `canvas_cairomakie.jl` shows how to draw a CairoMakie plot into a `GtkCanvas`.
- `canvas.jl` demonstrates use of `GtkCanvas`, which allows drawing with [Cairo](https://github.com/JuliaGraphics/Cairo.jl). Also shows how to change the cursor when it's over a certain widget.
- `canvas_cairomakie.jl` shows how to draw a [CairoMakie](https://github.com/MakieOrg/Makie.jl) plot into a `GtkCanvas`.
- `glarea.jl` shows how to use the `GtkGLArea` widget to draw using OpenGL.

## Lists
Expand Down
2 changes: 1 addition & 1 deletion examples/canvas.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ end
cursor(c, "crosshair")

# add the canvas to a window
win = GtkWindow("Canvas")
win = GtkWindow("Canvas", 300, 300)
win[] = c

# add an event controller to handle mouse clicks
Expand Down
2 changes: 1 addition & 1 deletion examples/canvas_cairomakie.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ t_range = 0.0:0.1:10.0
x = rand(length(t_range))
arr() = sin.(t_range) .* Gtk4.value(s) .+ x

canvas = GtkCanvas(; vexpand=true, hexpand=true)
canvas = GtkCanvas(400, 200; vexpand=true, hexpand=true)
b = push!(GtkBox(:v),canvas)
w = GtkWindow(b,"CairoMakie example")
s = GtkScale(:h,-5:5; draw_value = true)
Expand Down
2 changes: 1 addition & 1 deletion examples/columnview.jl
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ end

list = GtkColumnView(GtkSelectionModel(GtkSingleSelection(GListModel(filteredModel))); vexpand=true)
factory1 = GtkSignalListItemFactory(setup_cb, bind_cb)
col1 = GtkColumnViewColumn("name", factory1)
col1 = GtkColumnViewColumn("name", factory1; expand=true)
push!(list, col1)

factory2 = GtkSignalListItemFactory(setup_cb, bind2_cb)
Expand Down
2 changes: 1 addition & 1 deletion examples/filteredlistview.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Gtk4

win = GtkWindow("Listview demo with filter")
win = GtkWindow("Listview demo with filter", 300, 800)
box = GtkBox(:v)
entry = GtkSearchEntry()
sw = GtkScrolledWindow()
Expand Down
2 changes: 1 addition & 1 deletion examples/listbox.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Gtk4

win = GtkWindow("ListBox demo with filter")
win = GtkWindow("ListBox demo with filter", 300, 800)
box = GtkBox(:v)
entry = GtkSearchEntry()
sw = GtkScrolledWindow()
Expand Down
2 changes: 1 addition & 1 deletion gen/gen_gobject.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ skiplist=[
:watch_closure,:add_interface,:register_enum,:register_flags,:register_type,
:getv,:notify_by_pspec,:interface_find_property,:interface_install_property,:interface_list_properties]

GI.all_object_methods!(exprs,ns;skiplist=skiplist,object_skiplist=[:BindingGroup,:SignalGroup])
GI.all_object_methods!(exprs,ns;skiplist=skiplist,object_skiplist=[:BindingGroup,:SignalGroup], interface_helpers=false)

GI.write_to_file(path,"gobject_methods",toplevel)

Expand Down
2 changes: 1 addition & 1 deletion src/GLib/GLib.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export add_action, add_stateful_action

export get_gtk_property, set_gtk_property!, gtk_propertynames, bind_property, unbind_property
export bytestring, nothing_to_null, setproperties!, string_or_nothing, convert_if_not_null
export length_zt, err_buf, check_err
export length_zt, err_buf, check_err, GErrorException
export gtkdoc_const_url, gtkdoc_enum_url, gtkdoc_flags_url, gtkdoc_method_url,
gtkdoc_func_url, gtkdoc_struc_url

Expand Down
17 changes: 14 additions & 3 deletions src/GLib/gerror.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ struct GError
code::Cint
message::Ptr{UInt8}
end

message(err::GError) = bytestring(err.message)

#@make_gvalue(GError, Ptr{GError}, :boxed, (:g_error, :libgobject))
convert(::Type{GError}, err::Ptr{GError}) = GError(err)
g_type(::Type{GError}) = ccall((:g_error_get_type, libgobject), GType, ())
Expand All @@ -14,13 +17,21 @@ function err_buf()
err[] = Ptr{GError}(C_NULL)
err
end

struct GErrorException <: Exception
domain::UInt32
code::Cint
message::String
end

GErrorException(err::GError) = GErrorException(err.domain, err.code, bytestring(err.message))

function check_err(err::Base.RefValue{Ptr{GError}})
if err[] != C_NULL
gerror = GError(err[])
emsg = message(gerror)
ee = GErrorException(gerror)
ccall((:g_clear_error,libglib),Nothing,(Ptr{Ptr{GError}},),err)
error(emsg)
throw(ee)
end
end

message(err::GError) = bytestring(err.message)
3 changes: 2 additions & 1 deletion src/Gtk4.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ end

import .GLib: set_gtk_property!, get_gtk_property, run,
signal_handler_is_connected, signalnames,
GListModel
GListModel, start_main_loop, stop_main_loop

# define accessor methods in Gtk4

Expand Down Expand Up @@ -107,6 +107,7 @@ include("gl_area.jl")
include("lists.jl")
include("text.jl")
include("tree.jl")
include("deprecated.jl")
include("basic_exports.jl")

global const lib_version = VersionNumber(
Expand Down
8 changes: 8 additions & 0 deletions src/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ Related GTK function: [`gtk_widget_grab_focus`()]($(gtkdoc_method_url("gtk4","Wi
"""
grab_focus(w::GtkWidget) = G_.grab_focus(w)

"""
isrealized(w::GtkWidget)

Returns whether `w` is realized (that is, whether it has been associated with
a drawing surface).
"""
isrealized(w::GtkWidget) = G_.get_realized(w)

"""
activate(w::GtkWidget)

Expand Down
1 change: 1 addition & 0 deletions src/basic_exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export signal_connect, signal_handler_disconnect,
signal_handler_block, signal_handler_unblock, signal_handler_is_connected,
signal_emit, g_timeout_add, g_idle_add
export @guarded, @idle_add
export start_main_loop, stop_main_loop

# Gtk-specific event handling
export signal_emit,
Expand Down
4 changes: 4 additions & 0 deletions src/deprecated.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
GtkAdjustment(spinButton::GtkSpinButton) = G_.get_adjustment(spinButton)
GtkAdjustment(range::GtkRange) = G_.get_adjustment(range)
GtkAdjustment(scale::GtkScaleButton) = G_.get_adjustment(scale)

2 changes: 2 additions & 0 deletions src/events.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ function GtkShortcutController(widget::GtkWidget)
g
end

push!(sc::GtkShortcutController, s::GtkShortcut) = (G_.add_shortcut(sc,s);sc)

function GtkGestureClick(widget::GtkWidget,button=1)
g = G_.GestureClick_new()
button != 1 && G_.set_button(g, button)
Expand Down
Loading
Loading