Skip to content

Commit

Permalink
minor type stability fixes, docstrings, fix GVariant getter for string
Browse files Browse the repository at this point in the history
  • Loading branch information
jwahlstrand committed Feb 12, 2024
1 parent bc82cf8 commit 7332028
Show file tree
Hide file tree
Showing 12 changed files with 103 additions and 17 deletions.
45 changes: 41 additions & 4 deletions src/GLib/actions.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# actions
"""
activate(a::GAction, par = nothing)
Activates an action, optionally with a parameter `par`, which if given should be a GVariant.
"""
activate(a::GAction, par = nothing) = G_.activate(a, par)
GSimpleAction(name::AbstractString; kwargs...) = GSimpleAction(name, nothing; kwargs...)

function GSimpleAction(name::AbstractString, parameter::Type{T}; kwargs...) where T
Expand All @@ -22,12 +28,26 @@ function GSimpleAction(name::AbstractString, parameter::Type{T},
GSimpleAction(name, pvtype, GVariant(initial_state))
end

activate(a::GSimpleAction, par = nothing) = G_.activate(GAction(a), par)

"""
set_state(m::GSimpleAction, v)
Set the state of a stateful action.
"""
set_state(m::GSimpleAction, v) = set_state(m, GVariant(v))
set_state(m::GSimpleAction, v::GVariant) = G_.set_state(m,v)

# action maps
push!(m::GActionMap, a::GAction) = (G_.add_action(m,a); m)
delete!(m::GActionMap, a::AbstractString) = (G_.remove_action(m, a); m)
getindex(m::GActionMap, name::AbstractString) = G_.lookup_action(m, name)

"""
add_action(m::GActionMap, name::AbstractString, parameter::Type{T}, handler::Function)
Add an action with `name` and a parameter of type `T` to a `GActionMap`. Also connect a `handler` for the action's "activate" signal.
"""
function add_action(m::GActionMap, name::AbstractString,
parameter::Type{T}, handler::Function) where T
action = GSimpleAction(name, parameter)
Expand All @@ -36,23 +56,33 @@ function add_action(m::GActionMap, name::AbstractString,
action
end

"""
add_action(m::GActionMap, name::AbstractString, handler::Function)
Add an action with `name` to a `GActionMap`. Also connect a `handler` for the action's "activate" signal.
"""
function add_action(m::GActionMap, name::AbstractString, handler::Function)
add_action(m, name, Nothing, handler)
end

function add_action(m::GActionMap, name::AbstractString,
parameter::Type{T}, cb, user_data) where T
parameter::Type{T}, cb::Function, user_data) where T
action = GSimpleAction(name, parameter)
push!(m,GAction(action))
signal_connect(cb, action, :activate, Nothing,
(Ptr{GVariant},), false, user_data)
action
end

function add_action(m::GActionMap, name::AbstractString, cb, user_data)
function add_action(m::GActionMap, name::AbstractString, cb::Function, user_data)
add_action(m, name, Nothing, cb, user_data)
end

"""
add_stateful_action(m::GActionMap, name::AbstractString, parameter::Type{T}, initial_state, handler::Function)
Add a stateful action with `name`, a parameter of type `T`, and an initial state to a `GActionMap`. Also connect a `handler` for the action's "change-state" signal.
"""
function add_stateful_action(m::GActionMap, name::AbstractString,
parameter::Type{T}, initial_state,
handler::Function) where T
Expand All @@ -62,14 +92,19 @@ function add_stateful_action(m::GActionMap, name::AbstractString,
action
end

"""
add_stateful_action(m::GActionMap, name::AbstractString, initial_state, handler::Function)
Add a stateful action with `name` and an initial state to a `GActionMap`. Also connect a `handler` for the action's "change-state" signal.
"""
function add_stateful_action(m::GActionMap, name::AbstractString, initial_state,
handler::Function)
add_stateful_action(m, name, Nothing, initial_state, handler)
end

function add_stateful_action(m::GActionMap, name::AbstractString,
parameter::Type{T}, initial_state,
cb, user_data) where T
cb::Function, user_data) where T
action = GSimpleAction(name, parameter, initial_state)
push!(m,GAction(action))
signal_connect(cb, action, :change_state, Nothing,
Expand All @@ -78,20 +113,22 @@ function add_stateful_action(m::GActionMap, name::AbstractString,
end

function add_stateful_action(m::GActionMap, name::AbstractString, initial_state,
cb, user_data)
cb::Function, user_data)
add_stateful_action(m, name, Nothing, initial_state, cb, user_data)
end

# action groups
push!(g::GSimpleActionGroup, a) = (push!(GActionMap(g), GAction(a)); g)
delete!(g::GSimpleActionGroup, a::AbstractString) = (delete!(GActionMap(g), a); g)
getindex(g::GSimpleActionGroup, name::AbstractString) = getindex(GActionMap(g), name)
list_actions(g) = G_.list_actions(GActionGroup(g))

function GDBusActionGroup(app::GApplication, bus_name, object_path)
conn = G_.get_dbus_connection(app)
G_.get(conn, bus_name, object_path)
end

# menus
function GMenu(i::GMenuItem)
m = GMenu()
G_.set_submenu(i,m)
Expand Down
30 changes: 30 additions & 0 deletions src/GLib/gvalues.jl
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,11 @@ function getindex(gv::Base.Ref{GValue}, ::Type{Any})
end
#end

"""
get_gtk_property(w::GObject, name::AbstractString, ::Type{T})
Get a GObject property's value as type `T`.
"""
get_gtk_property(w::GObject, name::AbstractString, ::Type{T}) where T = get_gtk_property(w, String(name)::String, T)
get_gtk_property(w::GObject, name::Symbol, ::Type{T}) where T = get_gtk_property(w, String(name), T)
function get_gtk_property(w::GObject, name::String, ::Type{T}) where T
Expand All @@ -265,6 +270,16 @@ function get_gtk_property(w::GObject, name::String, ::Type{T}) where T
end
return val
end

"""
get_gtk_property(w::GObject, name::AbstractString)
Get a GObject property's value. The type of the returned value depends on the property, so this function's output is type unstable.
GObject properties are mapped onto Julia instance properties, so this function is equivalent to the syntax `w.name`.
See also [`set_gtk_property!`](@ref).
"""
get_gtk_property(w::GObject, name::AbstractString) = get_gtk_property(w, String(name)::String)
get_gtk_property(w::GObject, name::Symbol) = get_gtk_property(w, String(name))
function get_gtk_property(w::GObject, name::String)
Expand All @@ -279,7 +294,22 @@ function get_gtk_property(w::GObject, name::String)
return val
end

"""
set_gtk_property!(w::GObject, name, ::Type{T}, value)
Set a GObject property `name` (which can be a string or symbol) to `value` converted to type `T`.
"""
set_gtk_property!(w::GObject, name, ::Type{T}, value) where T = set_gtk_property!(w, name, convert(T, value))

"""
set_gtk_property!(w::GObject, name, value)
Set a GObject property `name` (which can be a string or symbol) to `value`. The type of `value` will be converted to match the property type, if possible.
GObject properties are mapped onto Julia instance properties, so note that this function is equivalent to the more convenient syntax `w.name = value`.
See also [`get_gtk_property`](@ref).
"""
set_gtk_property!(w::GObject, name::AbstractString, value) = set_gtk_property!(w::GObject, String(name)::String, value)
set_gtk_property!(w::GObject, name::Symbol, value) = set_gtk_property!(w::GObject, String(name), value)
function set_gtk_property!(w::GObject, name::String, value)
Expand Down
6 changes: 5 additions & 1 deletion src/GLib/gvariant.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ let variant_fns = Expr(:block)
(name, ctype, juliatype, g_value_fn, g_variant_fn) = fundamental_types[i]
if g_variant_fn !== :error && juliatype != Union{}
push!(variant_fns.args, :( GVariant(x::T) where {T <: $juliatype} = G_.$(Symbol("Variant_new_", g_variant_fn))(x)))
push!(variant_fns.args, :( getindex(gv::GVariant, ::Type{T}) where {T <: $juliatype} = G_.$(Symbol("get_", g_variant_fn))(gv)))
if g_variant_fn === :string
push!(variant_fns.args, :( getindex(gv::GVariant, ::Type{T}) where {T <: $juliatype} = G_.get_string(gv)[1]))
else
push!(variant_fns.args, :( getindex(gv::GVariant, ::Type{T}) where {T <: $juliatype} = G_.$(Symbol("get_", g_variant_fn))(gv)))
end
end
end
Core.eval(GLib, variant_fns)
Expand Down
7 changes: 4 additions & 3 deletions src/GLib/loop.jl
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,14 @@ end
"""
pause_main_loop(f)
Pauses the GLib eventloop around a function. Restores the original state of the eventloop after
calling the function.
Pauses the GLib event loop around a function. Restores the original state of the event loop after calling the function. This function does not pause the event loop if it is being run by a `GApplication`.
"""
function pause_main_loop(f)
was_running = is_loop_running()
if was_running && g_main_running[] == false
error("Main loop is running, but not via `glib_main`. Pausing the main loop inside a GApplication is not currently supported.")
warn("GLib main loop is running, but not via `glib_main`. Pausing the main loop inside a GApplication is not currently supported, so the function will be called without pausing.")
f()
return
end
was_running && stop_main_loop(true)
try
Expand Down
7 changes: 6 additions & 1 deletion src/GLib/signals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,11 @@ the given `id`.
signal_handler_is_connected(w::GObject, handler_id::Culong) =
ccall((:g_signal_handler_is_connected, libgobject), Cint, (Ptr{GObject}, Culong), w, handler_id) == 1

"""
signal_emit(w::GObject, sig::AbstractStringLike, ::Type{RT}, args...) where RT
Cause an object signal to be emitted. The return type `RT` and the correct number of arguments (of the correct type) must be provided. The argument list should exclude the `user_data` argument.
"""
function signal_emit(w::GObject, sig::AbstractStringLike, ::Type{RT}, args...) where RT
i = isa(sig, AbstractString) ? something(findfirst("::", sig), 0:-1) : (0:-1)
if !isempty(i)
Expand Down Expand Up @@ -422,7 +427,7 @@ end
Connect a callback `f` to the object's "notify::property" signal that will be
called whenever the property changes. The callback signature should be
`f(::Ptr, param::Ptr{GParamSpec}, user_data)` and should return `nothing`.
`f(::Ptr, param::Ptr{GParamSpec}, user_data)` and the function should return `nothing`.
"""
function on_notify(f, object::GObject, property::AbstractString, user_data = object, after = false)
signal_connect_generic(f, object, "notify::$property", Nothing, (Ptr{GParamSpec},), after, user_data)
Expand Down
2 changes: 1 addition & 1 deletion src/Gdk4.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function GdkRGBA(rgba::AbstractString)
r=GdkRGBA(0,0,0,0)
b=G_.parse(r,rgba)
if !b
error("Unable to parse into a color")
error("Unable to parse $rgba into a GdkRGBA")
end
r
end
Expand Down
2 changes: 1 addition & 1 deletion src/Gtk4.jl
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ end

end

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

Expand Down
4 changes: 2 additions & 2 deletions src/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,10 @@ Gets the `GdkMonitor` where `w` is displayed, or `nothing` if the widget is not
part of a widget hierarchy.
"""
function monitor(w::GtkWidget)
d = display(w)
d = display(w)::GdkDisplayLeaf
tl = toplevel(w)
tl === nothing && return nothing
s = G_.get_surface(GtkNative(tl))
s = G_.get_surface(GtkNative(tl))::GdkSurfaceLeaf
# sometimes `get_monitor_at_surface` returns NULL when it shouldn't
# should be unnecessary in a future version of GTK4_jll: https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/4917
try
Expand Down
8 changes: 5 additions & 3 deletions src/displays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Returns a tuple `(width,height)` that gives the primary monitor size for the
display where `widget` is being displayed, or the default display if `widget` is
unrealized or not given.
"""
function screen_size(widget=nothing)
function screen_size(widget=nothing)::Tuple{Int32,Int32}
if widget!== nothing && G_.get_realized(widget)
d=G_.get_display(widget)
else
Expand All @@ -15,8 +15,10 @@ function screen_size(widget=nothing)

m=G_.get_monitors(d)
m===nothing && error("Unable to get list of monitors")
length(m)==0 && error("No monitors found")
size(m[1])
ml=m::GListStoreLeaf
length(ml)==0 && error("No monitors found")
m1=ml[1]::GdkMonitorLeaf
size(m1)
end

# GtkImage (for fixed-size images, such as icons)
Expand Down
2 changes: 2 additions & 0 deletions src/events.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ Adds a shortcut specified by a string like "<Control>S" for an action (such as
"""
function add_action_shortcut(scc::GtkShortcutController,trigger::AbstractString,action::AbstractString)
t = GtkShortcutTrigger(trigger)
t === nothing && error("unable to parse $trigger into a GtkShortcutTrigger")
a = GtkShortcutAction("action($action)")
a === nothing && error("unable to parse action($action) into a GtkShortcutAction")
sc = GtkShortcut(t,a)
Gtk4.G_.add_shortcut(scc,sc)
end
Expand Down
3 changes: 2 additions & 1 deletion src/lists.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ widget's model is a `GtkStringList`.
"""
function selected_string!(d::GtkDropDown, s::AbstractString)
sl = G_.get_model(d)
isnothing(sl) && error("No model set in GtkDropDown")
isa(sl, GtkStringList) || error("This method only works if the model is a GtkStringList")
i = findfirst(==(s), sl)
isnothing(i) && error("String not found in model")
Expand Down Expand Up @@ -120,7 +121,7 @@ function GtkTreeListModel(root, passthrough, autoexpand, create_func)
ref, deref = GLib.gc_ref_closure(create_func)
GLib.glib_ref(rootlm)
ret = ccall(("gtk_tree_list_model_new", libgtk4), Ptr{GObject}, (Ptr{GObject}, Cint, Cint, Ptr{Nothing}, Ptr{Nothing}, Ptr{Nothing}), rootlm, passthrough, autoexpand, create_cfunc, ref, deref)
convert(GtkTreeListModel, ret, true)
GtkTreeListModelLeaf(ret, true)
end

"""
Expand Down
4 changes: 4 additions & 0 deletions test/action-group.jl
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ gv2 = GLib.GVariant(UInt8,2)
@test gv2 > gv1
@test gv2 >= gv1

# test string
gvs = GVariant("test")
@test gvs[String] == "test"

# test tuples
gvt = GLib.GVariant((true,3,6.5))
@test GLib.GVariantType(Tuple{Bool,Int,Float64}) == GLib.G_.get_type(gvt)
Expand Down

0 comments on commit 7332028

Please sign in to comment.