Skip to content

Commit

Permalink
add example of custom GtkWidget
Browse files Browse the repository at this point in the history
And misc. other minor things
  • Loading branch information
jwahlstrand committed May 30, 2024
1 parent c184328 commit 6d8d644
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 3 deletions.
3 changes: 2 additions & 1 deletion docs/src/howto/async.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ robustly.
Here is an example using [threads](https://docs.julialang.org/en/v1/manual/multi-threading/).
Notice that this example will freeze the UI during computation unless Julia is run with two
or more threads, for example by calling `julia -t2` or `julia -t1,1` to use the interactive
threadpool in recent versions of Julia.
thread pool in recent versions of Julia.
If an interactive thread pool exists, the GLib main loop will be started in an interactive thread.

```julia
using Gtk4
Expand Down
4 changes: 4 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@

## Toys
- `HDF5Viewer` is a more extended example that shows the contents of an HDF5 file. Uses `GtkBuilder`, `GtkColumnView`, and `GtkTextView` and does some work in a separate thread to keep the UI responsive.

## Experimental

- `custom_widget` shows how to define a custom GtkWidget with its own "snapshot" callback
67 changes: 67 additions & 0 deletions examples/custom_widget.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using Gtk4.GLib, Gtk4
import Gtk4.GLib: _GObjectClass
import Gtk4: _GtkWidgetClass
import Gtk4.Graphene: _GrapheneRect

function widget_measure(widget::Ptr{GObject}, orientation::Cint, for_size::Cint, minimum::Ptr{Cint}, natural::Ptr{Cint}, minimum_baseline::Ptr{Cint}, natural_baseline::Ptr{Cint})
unsafe_store!(minimum, Cint(100))
unsafe_store!(natural, Cint(100))
nothing
end

function widget_snapshot(widget_ptr::Ptr{GObject}, snapshot_ptr::Ptr{GObject})
t = GLib.G_OBJECT_CLASS_TYPE(widget_ptr)
t2 = GLib.G_OBJECT_CLASS_TYPE(snapshot_ptr)
widget = convert(GtkWidget, widget_ptr)
snapshot = convert(GtkSnapshot, snapshot_ptr)
w,h = size(widget)
Gtk4.G_.append_color(snapshot, GdkRGBA("red"), Ref(_GrapheneRect(0,0,w/2,h/2)))
Gtk4.G_.append_color(snapshot, GdkRGBA("green"), Ref(_GrapheneRect(w/2,0,w/2,h/2)))
Gtk4.G_.append_color(snapshot, GdkRGBA("yellow"), Ref(_GrapheneRect(0,h/2,w/2,h/2)))
Gtk4.G_.append_color(snapshot, GdkRGBA("blue"), Ref(_GrapheneRect(w/2,h/2,w/2,h/2)))
nothing
end

function object_class_init(class::Ptr{_GObjectClass}, user_data)
object_klass_ptr = Ptr{_GObjectClass}(class)
object_klass = unsafe_load(object_klass_ptr)
widget_klass_ptr = Ptr{_GtkWidgetClass}(class)
widget_klass = unsafe_load(widget_klass_ptr)
widget_klass.snapshot = @cfunction(widget_snapshot, Cvoid, (Ptr{GObject}, Ptr{GObject}))
widget_klass.measure = @cfunction(widget_measure, Cvoid, (Ptr{GObject}, Cint, Cint, Ptr{Cint}, Ptr{Cint}, Ptr{Cint}, Ptr{Cint}))
unsafe_store!(widget_klass_ptr, widget_klass)
nothing
end

mutable struct MyWidget <: GtkWidget
handle::Ptr{GObject}
end

const class_init = @cfunction(object_class_init, Cvoid, (Ptr{_GObjectClass}, Ptr{Cvoid}))

function register_new_widget()
base_gtype = GLib.g_type(GtkWidget)
tq=GLib.G_.type_query(base_gtype)
typeinfo=_GTypeInfo(tq.class_size,
C_NULL, # base_init
C_NULL, # base_finalize
class_init,
C_NULL, # class_finalize
C_NULL, # class_data
tq.instance_size,
0, # n_preallocs
C_NULL, # instance_init
C_NULL) # value_table
GLib.G_.type_register_static(GLib.g_type(GtkWidget),:MyWidget,Ref(typeinfo),GLib.TypeFlags_FINAL)
end

function create_widget(gtype)
h = ccall(("g_object_new", GLib.libgobject), Ptr{GObject}, (UInt64, Ptr{Cvoid}), gtype, C_NULL)
MyWidget(h)
end

gt=register_new_widget()
w = create_widget(gt)

win=GtkWindow("custom widget")
win[] = w
20 changes: 20 additions & 0 deletions src/GLib/gobject.jl
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,23 @@ See also [`bind_property`](@ref).
Related GTK function: [`g_binding_unbind`](https://docs.gtk.org/gobject/method.Binding.unbind.html)
"""
unbind_property(b::GBinding) = G_.unbind(b)

mutable struct _GObjectClass
g_type_class::_GTypeClass
construct_properties::Ptr{GLib._GSList{Ptr{Nothing}}}
constructor::Ptr{Nothing}
set_property::Ptr{Cvoid}
get_property::Ptr{Cvoid}
dispose::Ptr{Cvoid}
finalize::Ptr{Cvoid}
dispatch_properties_changed::Ptr{Cvoid}
notify::Ptr{Cvoid}
constructed::Ptr{Cvoid}
flags::UInt64
n_construct_properties::UInt64
pspecs::Ptr{Nothing}
n_pspecs::UInt64
pdummy1::Ptr{Nothing}
pdummy2::Ptr{Nothing}
pdummy3::Ptr{Nothing}
end
7 changes: 7 additions & 0 deletions src/GLib/listmodel.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
"""
GListStore(t)
Create a GListStore, which is an array of GObjects that implements the
GListModel interface. The argument `t` can be a Julia type corresponding to a
GObject type (such as `GtkWidget`) or a symbol (such as :GtkWidget).
"""
function GListStore(t)
t = g_type_from_name(Symbol(t))
t == 0 && error("Invalid GType")
Expand Down
4 changes: 2 additions & 2 deletions src/GLib/signals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -388,12 +388,12 @@ function __init__gmainloop__()
ccall((:g_source_set_callback, libglib), Nothing, (Ptr{Nothing}, Ptr{Nothing}, UInt, Ptr{Nothing}),
src, @cfunction(g_yield, Cint, (UInt,)), 1, C_NULL)

uv_int_setting = @load_preference("uv_loop_integration", "auto")
uv_int_setting = @load_preference("uv_loop_integration", "auto")::String
if uv_int_setting == "enabled"
uv_int_enabled[] = true
elseif uv_int_setting == "disabled"
uv_int_enabled[] = false
elseif uv_int_setting == "auto"
else # "auto" or anything else
# enabled by default only on Macs in an interactive session, where it prevents REPL lag
uv_int_enabled[] = Sys.isapple() && isinteractive()
end
Expand Down
2 changes: 2 additions & 0 deletions src/Graphene.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export _GrapheneRect, _GraphenePoint, _GrapheneMatrix, _GrapheneVec4, _GrapheneV
#eval(include("gen/graphene_methods"))
#eval(include("gen/graphene_functions"))

_GrapheneRect(x::Number,y::Number,w::Number,h::Number) = _GrapheneRect(_GraphenePoint(x,y),_GrapheneSize(w,h))

function __init__()
gtype_wrapper_cache_init()
gboxed_cache_init()
Expand Down
47 changes: 47 additions & 0 deletions src/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -327,3 +327,50 @@ function inhibit(app::GtkApplication, win::GtkWindow, flags, reason)
end

uninhibit(app::GtkApplication, cookie) = G_.uninhibit(app, cookie)

mutable struct _GtkWidgetClass
g_type_class::_GTypeClass
construct_properties::Ptr{GLib._GSList{Ptr{Nothing}}}
constructor::Ptr{Nothing}
set_property::Ptr{Cvoid}
get_property::Ptr{Cvoid}
dispose::Ptr{Cvoid}
finalize::Ptr{Cvoid}
dispatch_properties_changed::Ptr{Cvoid}
notify::Ptr{Cvoid}
constructed::Ptr{Cvoid}
flags::Csize_t
n_construct_properties::Csize_t
pspecs::Ptr{Nothing}
n_pspecs::Csize_t
pdummy1::Ptr{Nothing}
pdummy2::Ptr{Nothing}
pdummy3::Ptr{Nothing}
show::Ptr{Cvoid}
hide::Ptr{Cvoid}
map::Ptr{Cvoid}
unmap::Ptr{Cvoid}
realize::Ptr{Cvoid}
unrealize::Ptr{Cvoid}
root::Ptr{Cvoid}
unroot::Ptr{Cvoid}
size_allocate::Ptr{Cvoid}
state_flags_changed::Ptr{Cvoid}
direction_changed::Ptr{Cvoid}
get_request_mode::Ptr{Cvoid}
measure::Ptr{Cvoid}
mnemonic_activate::Ptr{Cvoid}
grab_focus::Ptr{Cvoid}
focus::Ptr{Cvoid}
set_focus_child::Ptr{Cvoid}
move_focus::Ptr{Cvoid}
keynav_failed::Ptr{Cvoid}
query_tooltip::Ptr{Cvoid}
compute_expand::Ptr{Cvoid}
css_changed::Ptr{Cvoid}
system_setting_changed::Ptr{Cvoid}
snapshot::Ptr{Cvoid}
contains::Ptr{Cvoid}
priv::Ptr{Nothing}
padding::Ptr{Ptr{Nothing}}
end

0 comments on commit 6d8d644

Please sign in to comment.