Julia interface to Gtk+-2 and Gtk+-3 GUI library (http://www.gtk.org/)
Disclaimer: some part of this API may not be finalized
Prior to using this library, you must install a version of libgtk on your computer. While this interface currently defaults to using Gtk+-2, it can be configured by editing Gtk/deps/ext.jl
and changing the integer valued gtk_version
variable.
The easiest method of installation is to use WinRPM.jl
:
- Pkg.add("WinRPM")
- WinRPM.install("gtk2")
- RPMbindir = Pkg.dir("WinRPM","deps","usr","$(Sys.ARCH)-w64-mingw32","sys-root","mingw","bin")
- ENV["PATH"]=ENV["PATH"]*";"*RPMbindir
You may need to repeat steps 3 and 4 every time you restart julia, or put these two lines in your $HOME/.juliarc.jl file
I use MacPorts:
port install gtk2 +quartz -x11 gtk3 +quartz -x11
(this may require that you first remove Cairo and Pango, I like to put this in my "/opt/local/etc/macports/variants.conf" file as "+no_x11 -x11 +quartz" before installing anything to minimize conflicts)- push!(DL_LOAD_PATH,"/opt/local/lib") You will need to repeat step 2 every time you restart julia, or put this line in your ~/.juliarc.jl file.
If you want to use Homebrew, the built-in formula is deficient (it does not support the Quartz back-end). See JuliaPackaging/Homebrew.jl#27 for possible eventual workarounds.
Try any of the following until something is successful:
aptitude install libgtk2.0-0 libgtk-3-0
apt-get install libgtk2.0-0 libgtk-3-0
yum install gtk2 gtk3
On some distributions you can also install a devhelp
package to have a local copy of the Gtk documentation.
This Gtk wrapper attempts to expose all of the power of the Gtk library in a simple, uniform interface. The structure and names employed should be easily familiar to anyone browsing the Gtk documentation or example code, or anyone who has prior experience with Gtk.
There is also a more detailed description in tutorial style, as well as a property/hierarchy browser and function reference.
Gtk object can be referenced by their Gtk names (which almost always have a name like GtkWindow), their interfaces (which will have an I
prefixed to their name, such as GtkContainerI), or their "short name" (which is generally just the Gtk name without the "Gtk", for example, Window). You can call using Gtk
to import the regular names, or using Gtk.ShortNames
to import the shorter names. You can also call import Gtk
, and then access either the regular or short names (e.g. Gtk.Window
or Gtk.GtkWindow
).
All objects in Gtk are intended to behave uniformly. This means that all objects will try to act as container objects. Indexing into an object (by number), or iterating the object will return a list of its contents or child objects. This also means that constructors are called with information on the elements that they contain. For example, when you create a button, you can specify either the embedded text or another widget!
Gtk.Button("This is a button")
Gtk.Button(Gtk.Label("Click me"))
On the flip side, you can assign child widgets to indices, or push!
them onto the list of child widgets, for any object which derives from a GtkContainerI. Of special note is the anti-object GtkNullContainer. This is not a Gtk Object. However, it can be used to prevent the creation of a default container, and it has the special behavior that it will remove any object added to it from its existing parent (although the standard operations like splice!
and delete!
also exist, and are typically preferable).
The properties of any object can be accessed by treating the object as an Associative dictionary. Displaying a GtkObjectI at the REPL-prompt will show you all of the properties that can be set on the object. Or you can view the Gtk documentation online. Indexing is typically done using a symbol, but you can also use a string. In property names, you can replace -
with _
as shown below.
When retrieving a property, you must specify the output type. Specifying the input type when setting a property is strictly optional.
Some Examples:
w = GtkWindow("Title")
show(STDOUT, w) # without the STDOUT parameter, show(w) would
# make the window visible on the screen, instead
# of printing the information in the REPL
w[:title,String]
w[:title] = "New title"
w[:urgency_hint,Bool] = true
There are two entry points to the API for handling signals: Simple and robust OR fast and precise.
You can remove signal handlers by their id using signal_handler_disconnect
or temporarily block them by id using signal_handler_block
and signal_handler_unblock
Upon entry to the signal handler, Julia will unpack the arguments it received into native types:
id = signal_connect(widget, :event) do obj, args...
println("That tickles: $args")
nothing
end
See section on Extending Gtk's Functionality with new GValue<->Julia auto-conversions at the end of this document for details on the auto-unpacking implementation.
If you want pre-optimized event handlers, you will need to specify the interface types when creating the signal handlers. (There are a few on_signal_
convenience functions which do this, often in conjunction with setting other flags needed for the signal handler to function). You will often find it necessary to refer to the Gtk documentation for the signals API for Gtk callbacks:
- Gtk+-2
- Gtk+-3
Note that the ArgType argument only specifies the type for the middle arguments. The type of the first and last arguments are determined automatically.
Example:
function on_signal_event(ptr, args, widget)
println("That tickles")
nothing
end
id = signal_connect(widget, :event, Void, (ArgType,))
## OR
id = signal_connect(widget, :event, Void, (ArgType,)) do ptr, args, obj
println("That tickles")
nothing
end
In addition to listening for events, you can trigger your own:
#syntax: signal_emit(w::GObject, sig::Union(String,Symbol), RT::Type, args...)
signal_emit(widget, :event, Void, 42)
Note: the return type and argument types do not need to match the spec. However, the length of the args list MUST exactly match the length of the ArgType's list.
warning: this API has not been completely finalized
Gtk._
(not exported), Gtk.G_
(exported by ShortNames), and Gtk.GAccessor
(exported by Gtk) all refer to the same module: a collection of auto-generated method stubs for calling get/set methods on the GtkObjects. The difference between a get and set method is based upon the number of arguments.
Example usage:
bytestring(Gtk._.title(Window("my title")))
G_.title(Window("my title"), "my new title")
GAccessor.size(Window("what size?"))
Note that because these are auto-generated, you will often need to do your own gc-management at the interface. For example, the string returned by title must not be freed or modified. Since the code auto-generator cannot know this, it simply returns the raw pointer.
+- Any
. +- AbstractArray = AbstractArray{GValue,1}
. . +- MatrixStrided = MatrixStrided{T}
. . +- Ranges = Ranges{T}
. . . +- GtkTextRange
. +- GError
. +- GObject = GObjectI
. +- GObjectI
. . +- GObjectAny = GObjectAny{Name}
. . +- GdkPixbuf
. . +- GtkStatusIcon
. . +- GtkTextBuffer
. . +- GtkTextMark
. . +- GtkTextTag
. . +- GtkWidgetI
. . . +- Canvas = GtkCanvas
. . . +- GtkCanvas
. . . +- GtkComboBoxText
. . . +- GtkContainerI
. . . . +- GtkBinI
. . . . . +- GtkAlignment
. . . . . +- GtkAspectFrame
. . . . . +- GtkButton
. . . . . +- GtkCheckButton
. . . . . +- GtkExpander
. . . . . +- GtkFrame
. . . . . +- GtkLinkButton
. . . . . +- GtkRadioButton
. . . . . +- GtkToggleButton
. . . . . +- GtkVolumeButton
. . . . . +- GtkWindowI
. . . . . . +- GtkDialogI
. . . . . . . +- GtkFileChooserDialog
. . . . . . +- GtkWindow
. . . . . . +- Window = GtkWindow
. . . . +- GtkBoxI
. . . . . +- GtkBox
. . . . . +- GtkButtonBox
. . . . . +- GtkStatusbar
. . . . +- GtkGrid
. . . . +- GtkLayout
. . . . +- GtkNotebook
. . . . +- GtkNullContainer
. . . . +- GtkOverlay
. . . . +- GtkPaned
. . . . +- GtkRadioButtonGroup
. . . . +- GtkTable
. . . +- GtkEntry
. . . +- GtkImage
. . . +- GtkLabel
. . . +- GtkProgressBar
. . . +- GtkScale
. . . +- GtkSpinButton
. . . +- GtkSpinner
. . . +- GtkSwitch
. . . +- GtkTextView
. +- GParamSpec
. +- GSList = GSList{T}
. +- GValue
. +- GdkEventI
. . +- GdkEventAny
. . +- GdkEventButton
. . +- GdkEventCrossing
. . +- GdkEventKey
. . +- GdkEventMotion
. . +- GdkEventScroll
. +- GdkPoint
. +- GdkRectangle
. +- GtkTextIter
. +- MouseHandler
. +- RGB
. +- RGBA
New Gtk types can be most easily added by using the Gtk.@GTypes macro:
Gtk.@GTypes GTypeName <: GParentName
and then defining the appropriate outer constructors. Pay attention to existing constructors that already exist, though, to avoid confusion: the first argument to a GtkContainer may optionally be its first child widget. And keyword arguments are reserved for setting properties after construction.
New GValue-to-Julia conversions can be implemented via the Gtk.make_gvalue(pass_x,as_ctype,to_gtype,with_id,allow_reverse::Bool=true)
function. This adds all of the appropriate methods to getindex, setindex!, and gvalue to handle converting this value to and from a GValue.
pass_x
is the Julia typeas_ctype
is the type for ccallto_gtype
is the name of theg_value_get_*
g_value_set_*
method to usewith_id
specifies the type identifier. It must resolve to an Int, but can either be a variable, and Integer, or a tuple of the type name and library where the_get_type
function can be calledallow_reverse
specifies whether this entry should be used for auto-unpacking
Note that this calls eval on its arguments in the current module, so if you want to use a symbol from Gtk (such as Gtk.libgtk
, make sure you give the fully qualified name). You will also need to ensure the appropriate convert methods exist to translate from pass_x
to as_ctype
and back. make_gvalue
does a few automatic transformations:
- if the
to_gtype
is:string
or:static_string
, make_gvalue will insert calls to bytestring - if the
to_gtype
is:pointer
or:boxed
, make_gvalue will insert code (a call toGtk.mutable
) that converts fromType
->Ptr{Type}
in thesetindex!
method. Providing a conversion fromPtr{Type}
->Type
must be handled by the user.
For example:
Gtk.make_gvalue(Gtk.GdkRectangle, Ptr{Gtk.GdkRectangle}, :boxed, (:gdk_rectangle,:(Gtk.libgdk)))
Base.convert(::Type{Gtk.GdkRectangle}, rect::Ptr{Gtk.GdkRectangle}) = unsafe_load(rect)