diff options
Diffstat (limited to 'vendor/github.com/gotk3/gotk3/glib/glib.go')
-rw-r--r-- | vendor/github.com/gotk3/gotk3/glib/glib.go | 1371 |
1 files changed, 1371 insertions, 0 deletions
diff --git a/vendor/github.com/gotk3/gotk3/glib/glib.go b/vendor/github.com/gotk3/gotk3/glib/glib.go new file mode 100644 index 0000000..523a711 --- /dev/null +++ b/vendor/github.com/gotk3/gotk3/glib/glib.go @@ -0,0 +1,1371 @@ +// Copyright (c) 2013-2014 Conformal Systems <info@conformal.com> +// +// This file originated from: http://opensource.conformal.com/ +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// Package glib provides Go bindings for GLib 2. Supports version 2.36 +// and later. +package glib + +// #cgo pkg-config: gio-2.0 glib-2.0 gobject-2.0 +// #include <gio/gio.h> +// #include <glib.h> +// #include <glib-object.h> +// #include "glib.go.h" +import "C" + +import ( + "errors" + "fmt" + "os" + "reflect" + "runtime" + "sync" + "unsafe" +) + +/* + * Type conversions + */ + +func gbool(b bool) C.gboolean { + if b { + return C.gboolean(1) + } + return C.gboolean(0) +} +func gobool(b C.gboolean) bool { + if b != 0 { + return true + } + return false +} + +/* + * Unexported vars + */ + +type closureContext struct { + rf reflect.Value + userData reflect.Value +} + +var ( + errNilPtr = errors.New("cgo returned unexpected nil pointer") + + closures = struct { + sync.RWMutex + m map[*C.GClosure]closureContext + }{ + m: make(map[*C.GClosure]closureContext), + } + + signals = make(map[SignalHandle]*C.GClosure) +) + +/* + * Constants + */ + +// Type is a representation of GLib's GType. +type Type uint + +const ( + TYPE_INVALID Type = C.G_TYPE_INVALID + TYPE_NONE Type = C.G_TYPE_NONE + TYPE_INTERFACE Type = C.G_TYPE_INTERFACE + TYPE_CHAR Type = C.G_TYPE_CHAR + TYPE_UCHAR Type = C.G_TYPE_UCHAR + TYPE_BOOLEAN Type = C.G_TYPE_BOOLEAN + TYPE_INT Type = C.G_TYPE_INT + TYPE_UINT Type = C.G_TYPE_UINT + TYPE_LONG Type = C.G_TYPE_LONG + TYPE_ULONG Type = C.G_TYPE_ULONG + TYPE_INT64 Type = C.G_TYPE_INT64 + TYPE_UINT64 Type = C.G_TYPE_UINT64 + TYPE_ENUM Type = C.G_TYPE_ENUM + TYPE_FLAGS Type = C.G_TYPE_FLAGS + TYPE_FLOAT Type = C.G_TYPE_FLOAT + TYPE_DOUBLE Type = C.G_TYPE_DOUBLE + TYPE_STRING Type = C.G_TYPE_STRING + TYPE_POINTER Type = C.G_TYPE_POINTER + TYPE_BOXED Type = C.G_TYPE_BOXED + TYPE_PARAM Type = C.G_TYPE_PARAM + TYPE_OBJECT Type = C.G_TYPE_OBJECT + TYPE_VARIANT Type = C.G_TYPE_VARIANT +) + +// Name is a wrapper around g_type_name(). +func (t Type) Name() string { + return C.GoString((*C.char)(C.g_type_name(C.GType(t)))) +} + +// Depth is a wrapper around g_type_depth(). +func (t Type) Depth() uint { + return uint(C.g_type_depth(C.GType(t))) +} + +// Parent is a wrapper around g_type_parent(). +func (t Type) Parent() Type { + return Type(C.g_type_parent(C.GType(t))) +} + +// UserDirectory is a representation of GLib's GUserDirectory. +type UserDirectory int + +const ( + USER_DIRECTORY_DESKTOP UserDirectory = C.G_USER_DIRECTORY_DESKTOP + USER_DIRECTORY_DOCUMENTS UserDirectory = C.G_USER_DIRECTORY_DOCUMENTS + USER_DIRECTORY_DOWNLOAD UserDirectory = C.G_USER_DIRECTORY_DOWNLOAD + USER_DIRECTORY_MUSIC UserDirectory = C.G_USER_DIRECTORY_MUSIC + USER_DIRECTORY_PICTURES UserDirectory = C.G_USER_DIRECTORY_PICTURES + USER_DIRECTORY_PUBLIC_SHARE UserDirectory = C.G_USER_DIRECTORY_PUBLIC_SHARE + USER_DIRECTORY_TEMPLATES UserDirectory = C.G_USER_DIRECTORY_TEMPLATES + USER_DIRECTORY_VIDEOS UserDirectory = C.G_USER_DIRECTORY_VIDEOS +) + +const USER_N_DIRECTORIES int = C.G_USER_N_DIRECTORIES + +/* + * GApplicationFlags + */ + +type ApplicationFlags int + +const ( + APPLICATION_FLAGS_NONE ApplicationFlags = C.G_APPLICATION_FLAGS_NONE + APPLICATION_IS_SERVICE ApplicationFlags = C.G_APPLICATION_IS_SERVICE + APPLICATION_HANDLES_OPEN ApplicationFlags = C.G_APPLICATION_HANDLES_OPEN + APPLICATION_HANDLES_COMMAND_LINE ApplicationFlags = C.G_APPLICATION_HANDLES_COMMAND_LINE + APPLICATION_SEND_ENVIRONMENT ApplicationFlags = C.G_APPLICATION_SEND_ENVIRONMENT + APPLICATION_NON_UNIQUE ApplicationFlags = C.G_APPLICATION_NON_UNIQUE +) + +// goMarshal is called by the GLib runtime when a closure needs to be invoked. +// The closure will be invoked with as many arguments as it can take, from 0 to +// the full amount provided by the call. If the closure asks for more parameters +// than there are to give, a warning is printed to stderr and the closure is +// not run. +// +//export goMarshal +func goMarshal(closure *C.GClosure, retValue *C.GValue, + nParams C.guint, params *C.GValue, + invocationHint C.gpointer, marshalData *C.GValue) { + + // Get the context associated with this callback closure. + closures.RLock() + cc := closures.m[closure] + closures.RUnlock() + + // Get number of parameters passed in. If user data was saved with the + // closure context, increment the total number of parameters. + nGLibParams := int(nParams) + nTotalParams := nGLibParams + if cc.userData.IsValid() { + nTotalParams++ + } + + // Get number of parameters from the callback closure. If this exceeds + // the total number of marshaled parameters, a warning will be printed + // to stderr, and the callback will not be run. + nCbParams := cc.rf.Type().NumIn() + if nCbParams > nTotalParams { + fmt.Fprintf(os.Stderr, + "too many closure args: have %d, max allowed %d\n", + nCbParams, nTotalParams) + return + } + + // Create a slice of reflect.Values as arguments to call the function. + gValues := gValueSlice(params, nCbParams) + args := make([]reflect.Value, 0, nCbParams) + + // Fill beginning of args, up to the minimum of the total number of callback + // parameters and parameters from the glib runtime. + for i := 0; i < nCbParams && i < nGLibParams; i++ { + v := &Value{&gValues[i]} + val, err := v.GoValue() + if err != nil { + fmt.Fprintf(os.Stderr, + "no suitable Go value for arg %d: %v\n", i, err) + return + } + rv := reflect.ValueOf(val) + args = append(args, rv.Convert(cc.rf.Type().In(i))) + } + + // If non-nil user data was passed in and not all args have been set, + // get and set the reflect.Value directly from the GValue. + if cc.userData.IsValid() && len(args) < cap(args) { + args = append(args, cc.userData.Convert(cc.rf.Type().In(nCbParams-1))) + } + + // Call closure with args. If the callback returns one or more + // values, save the GValue equivalent of the first. + rv := cc.rf.Call(args) + if retValue != nil && len(rv) > 0 { + if g, err := GValue(rv[0].Interface()); err != nil { + fmt.Fprintf(os.Stderr, + "cannot save callback return value: %v", err) + } else { + *retValue = *g.native() + } + } +} + +// gValueSlice converts a C array of GValues to a Go slice. +func gValueSlice(values *C.GValue, nValues int) (slice []C.GValue) { + header := (*reflect.SliceHeader)((unsafe.Pointer(&slice))) + header.Cap = nValues + header.Len = nValues + header.Data = uintptr(unsafe.Pointer(values)) + return +} + +/* + * Main event loop + */ + +type SourceHandle uint + +// IdleAdd adds an idle source to the default main event loop +// context. After running once, the source func will be removed +// from the main event loop, unless f returns a single bool true. +// +// This function will cause a panic when f eventually runs if the +// types of args do not match those of f. +func IdleAdd(f interface{}, args ...interface{}) (SourceHandle, error) { + // f must be a func with no parameters. + rf := reflect.ValueOf(f) + if rf.Type().Kind() != reflect.Func { + return 0, errors.New("f is not a function") + } + + // Create an idle source func to be added to the main loop context. + idleSrc := C.g_idle_source_new() + if idleSrc == nil { + return 0, errNilPtr + } + return sourceAttach(idleSrc, rf, args...) +} + +// TimeoutAdd adds an timeout source to the default main event loop +// context. After running once, the source func will be removed +// from the main event loop, unless f returns a single bool true. +// +// This function will cause a panic when f eventually runs if the +// types of args do not match those of f. +// timeout is in milliseconds +func TimeoutAdd(timeout uint, f interface{}, args ...interface{}) (SourceHandle, error) { + // f must be a func with no parameters. + rf := reflect.ValueOf(f) + if rf.Type().Kind() != reflect.Func { + return 0, errors.New("f is not a function") + } + + // Create a timeout source func to be added to the main loop context. + timeoutSrc := C.g_timeout_source_new(C.guint(timeout)) + if timeoutSrc == nil { + return 0, errNilPtr + } + + return sourceAttach(timeoutSrc, rf, args...) +} + +// sourceAttach attaches a source to the default main loop context. +func sourceAttach(src *C.struct__GSource, rf reflect.Value, args ...interface{}) (SourceHandle, error) { + if src == nil { + return 0, errNilPtr + } + + // rf must be a func with no parameters. + if rf.Type().Kind() != reflect.Func { + C.g_source_destroy(src) + return 0, errors.New("rf is not a function") + } + + // Create a new GClosure from f that invalidates itself when + // f returns false. The error is ignored here, as this will + // always be a function. + var closure *C.GClosure + closure, _ = ClosureNew(rf.Interface(), args...) + + // Remove closure context when closure is finalized. + C._g_closure_add_finalize_notifier(closure) + + // Set closure to run as a callback when the idle source runs. + C.g_source_set_closure(src, closure) + + // Attach the idle source func to the default main event loop + // context. + cid := C.g_source_attach(src, nil) + return SourceHandle(cid), nil +} + +/* + * Miscellaneous Utility Functions + */ + +// GetHomeDir is a wrapper around g_get_home_dir(). +func GetHomeDir() string { + c := C.g_get_home_dir() + return C.GoString((*C.char)(c)) +} + +// GetUserCacheDir is a wrapper around g_get_user_cache_dir(). +func GetUserCacheDir() string { + c := C.g_get_user_cache_dir() + return C.GoString((*C.char)(c)) +} + +// GetUserDataDir is a wrapper around g_get_user_data_dir(). +func GetUserDataDir() string { + c := C.g_get_user_data_dir() + return C.GoString((*C.char)(c)) +} + +// GetUserConfigDir is a wrapper around g_get_user_config_dir(). +func GetUserConfigDir() string { + c := C.g_get_user_config_dir() + return C.GoString((*C.char)(c)) +} + +// GetUserRuntimeDir is a wrapper around g_get_user_runtime_dir(). +func GetUserRuntimeDir() string { + c := C.g_get_user_runtime_dir() + return C.GoString((*C.char)(c)) +} + +// GetUserSpecialDir is a wrapper around g_get_user_special_dir(). A +// non-nil error is returned in the case that g_get_user_special_dir() +// returns NULL to differentiate between NULL and an empty string. +func GetUserSpecialDir(directory UserDirectory) (string, error) { + c := C.g_get_user_special_dir(C.GUserDirectory(directory)) + if c == nil { + return "", errNilPtr + } + return C.GoString((*C.char)(c)), nil +} + +/* + * GObject + */ + +// IObject is an interface type implemented by Object and all types which embed +// an Object. It is meant to be used as a type for function arguments which +// require GObjects or any subclasses thereof. +type IObject interface { + toGObject() *C.GObject + toObject() *Object +} + +// Object is a representation of GLib's GObject. +type Object struct { + GObject *C.GObject +} + +func (v *Object) toGObject() *C.GObject { + if v == nil { + return nil + } + return v.native() +} + +func (v *Object) toObject() *Object { + return v +} + +// newObject creates a new Object from a GObject pointer. +func newObject(p *C.GObject) *Object { + return &Object{GObject: p} +} + +// native returns a pointer to the underlying GObject. +func (v *Object) native() *C.GObject { + if v == nil || v.GObject == nil { + return nil + } + p := unsafe.Pointer(v.GObject) + return C.toGObject(p) +} + +// Take wraps a unsafe.Pointer as a glib.Object, taking ownership of it. +// This function is exported for visibility in other gotk3 packages and +// is not meant to be used by applications. +func Take(ptr unsafe.Pointer) *Object { + obj := newObject(ToGObject(ptr)) + + if obj.IsFloating() { + obj.RefSink() + } else { + obj.Ref() + } + + runtime.SetFinalizer(obj, (*Object).Unref) + return obj +} + +// Native returns a pointer to the underlying GObject. +func (v *Object) Native() uintptr { + return uintptr(unsafe.Pointer(v.native())) +} + +// IsA is a wrapper around g_type_is_a(). +func (v *Object) IsA(typ Type) bool { + return gobool(C.g_type_is_a(C.GType(v.TypeFromInstance()), C.GType(typ))) +} + +// TypeFromInstance is a wrapper around g_type_from_instance(). +func (v *Object) TypeFromInstance() Type { + c := C._g_type_from_instance(C.gpointer(unsafe.Pointer(v.native()))) + return Type(c) +} + +// ToGObject type converts an unsafe.Pointer as a native C GObject. +// This function is exported for visibility in other gotk3 packages and +// is not meant to be used by applications. +func ToGObject(p unsafe.Pointer) *C.GObject { + return C.toGObject(p) +} + +// Ref is a wrapper around g_object_ref(). +func (v *Object) Ref() { + C.g_object_ref(C.gpointer(v.GObject)) +} + +// Unref is a wrapper around g_object_unref(). +func (v *Object) Unref() { + C.g_object_unref(C.gpointer(v.GObject)) +} + +// RefSink is a wrapper around g_object_ref_sink(). +func (v *Object) RefSink() { + C.g_object_ref_sink(C.gpointer(v.GObject)) +} + +// IsFloating is a wrapper around g_object_is_floating(). +func (v *Object) IsFloating() bool { + c := C.g_object_is_floating(C.gpointer(v.GObject)) + return gobool(c) +} + +// ForceFloating is a wrapper around g_object_force_floating(). +func (v *Object) ForceFloating() { + C.g_object_force_floating(v.GObject) +} + +// StopEmission is a wrapper around g_signal_stop_emission_by_name(). +func (v *Object) StopEmission(s string) { + cstr := C.CString(s) + defer C.free(unsafe.Pointer(cstr)) + C.g_signal_stop_emission_by_name((C.gpointer)(v.GObject), + (*C.gchar)(cstr)) +} + +// Set is a wrapper around g_object_set(). However, unlike +// g_object_set(), this function only sets one name value pair. Make +// multiple calls to this function to set multiple properties. +func (v *Object) Set(name string, value interface{}) error { + return v.SetProperty(name, value) + /* + cstr := C.CString(name) + defer C.free(unsafe.Pointer(cstr)) + + if _, ok := value.(Object); ok { + value = value.(Object).GObject + } + + // Can't call g_object_set() as it uses a variable arg list, use a + // wrapper instead + var p unsafe.Pointer + switch v := value.(type) { + case bool: + c := gbool(v) + p = unsafe.Pointer(&c) + + case int8: + c := C.gint8(v) + p = unsafe.Pointer(&c) + + case int16: + c := C.gint16(v) + p = unsafe.Pointer(&c) + + case int32: + c := C.gint32(v) + p = unsafe.Pointer(&c) + + case int64: + c := C.gint64(v) + p = unsafe.Pointer(&c) + + case int: + c := C.gint(v) + p = unsafe.Pointer(&c) + + case uint8: + c := C.guchar(v) + p = unsafe.Pointer(&c) + + case uint16: + c := C.guint16(v) + p = unsafe.Pointer(&c) + + case uint32: + c := C.guint32(v) + p = unsafe.Pointer(&c) + + case uint64: + c := C.guint64(v) + p = unsafe.Pointer(&c) + + case uint: + c := C.guint(v) + p = unsafe.Pointer(&c) + + case uintptr: + p = unsafe.Pointer(C.gpointer(v)) + + case float32: + c := C.gfloat(v) + p = unsafe.Pointer(&c) + + case float64: + c := C.gdouble(v) + p = unsafe.Pointer(&c) + + case string: + cstr := C.CString(v) + defer C.g_free(C.gpointer(unsafe.Pointer(cstr))) + p = unsafe.Pointer(&cstr) + + default: + if pv, ok := value.(unsafe.Pointer); ok { + p = pv + } else { + val := reflect.ValueOf(value) + switch val.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, + reflect.Int32, reflect.Int64: + c := C.int(val.Int()) + p = unsafe.Pointer(&c) + + case reflect.Uintptr, reflect.Ptr, reflect.UnsafePointer: + p = unsafe.Pointer(C.gpointer(val.Pointer())) + } + } + } + if p == nil { + return errors.New("Unable to perform type conversion") + } + C._g_object_set_one(C.gpointer(v.GObject), (*C.gchar)(cstr), p) + return nil*/ +} + +// GetPropertyType returns the Type of a property of the underlying GObject. +// If the property is missing it will return TYPE_INVALID and an error. +func (v *Object) GetPropertyType(name string) (Type, error) { + cstr := C.CString(name) + defer C.free(unsafe.Pointer(cstr)) + + paramSpec := C.g_object_class_find_property(C._g_object_get_class(v.native()), (*C.gchar)(cstr)) + if paramSpec == nil { + return TYPE_INVALID, errors.New("couldn't find Property") + } + return Type(paramSpec.value_type), nil +} + +// GetProperty is a wrapper around g_object_get_property(). +func (v *Object) GetProperty(name string) (interface{}, error) { + cstr := C.CString(name) + defer C.free(unsafe.Pointer(cstr)) + + t, err := v.GetPropertyType(name) + if err != nil { + return nil, err + } + + p, err := ValueInit(t) + if err != nil { + return nil, errors.New("unable to allocate value") + } + C.g_object_get_property(v.GObject, (*C.gchar)(cstr), p.native()) + return p.GoValue() +} + +// SetProperty is a wrapper around g_object_set_property(). +func (v *Object) SetProperty(name string, value interface{}) error { + cstr := C.CString(name) + defer C.free(unsafe.Pointer(cstr)) + + if _, ok := value.(Object); ok { + value = value.(Object).GObject + } + + p, err := GValue(value) + if err != nil { + return errors.New("Unable to perform type conversion") + } + C.g_object_set_property(v.GObject, (*C.gchar)(cstr), p.native()) + return nil +} + +// pointerVal attempts to return an unsafe.Pointer for value. +// Not all types are understood, in which case a nil Pointer +// is returned. +/*func pointerVal(value interface{}) unsafe.Pointer { + var p unsafe.Pointer + switch v := value.(type) { + case bool: + c := gbool(v) + p = unsafe.Pointer(&c) + + case int8: + c := C.gint8(v) + p = unsafe.Pointer(&c) + + case int16: + c := C.gint16(v) + p = unsafe.Pointer(&c) + + case int32: + c := C.gint32(v) + p = unsafe.Pointer(&c) + + case int64: + c := C.gint64(v) + p = unsafe.Pointer(&c) + + case int: + c := C.gint(v) + p = unsafe.Pointer(&c) + + case uint8: + c := C.guchar(v) + p = unsafe.Pointer(&c) + + case uint16: + c := C.guint16(v) + p = unsafe.Pointer(&c) + + case uint32: + c := C.guint32(v) + p = unsafe.Pointer(&c) + + case uint64: + c := C.guint64(v) + p = unsafe.Pointer(&c) + + case uint: + c := C.guint(v) + p = unsafe.Pointer(&c) + + case uintptr: + p = unsafe.Pointer(C.gpointer(v)) + + case float32: + c := C.gfloat(v) + p = unsafe.Pointer(&c) + + case float64: + c := C.gdouble(v) + p = unsafe.Pointer(&c) + + case string: + cstr := C.CString(v) + defer C.free(unsafe.Pointer(cstr)) + p = unsafe.Pointer(cstr) + + default: + if pv, ok := value.(unsafe.Pointer); ok { + p = pv + } else { + val := reflect.ValueOf(value) + switch val.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, + reflect.Int32, reflect.Int64: + c := C.int(val.Int()) + p = unsafe.Pointer(&c) + + case reflect.Uintptr, reflect.Ptr, reflect.UnsafePointer: + p = unsafe.Pointer(C.gpointer(val.Pointer())) + } + } + } + + return p +}*/ + +/* + * GObject Signals + */ + +// Emit is a wrapper around g_signal_emitv() and emits the signal +// specified by the string s to an Object. Arguments to callback +// functions connected to this signal must be specified in args. Emit() +// returns an interface{} which must be type asserted as the Go +// equivalent type to the return value for native C callback. +// +// Note that this code is unsafe in that the types of values in args are +// not checked against whether they are suitable for the callback. +func (v *Object) Emit(s string, args ...interface{}) (interface{}, error) { + cstr := C.CString(s) + defer C.free(unsafe.Pointer(cstr)) + + // Create array of this instance and arguments + valv := C.alloc_gvalue_list(C.int(len(args)) + 1) + defer C.free(unsafe.Pointer(valv)) + + // Add args and valv + val, err := GValue(v) + if err != nil { + return nil, errors.New("Error converting Object to GValue: " + err.Error()) + } + C.val_list_insert(valv, C.int(0), val.native()) + for i := range args { + val, err := GValue(args[i]) + if err != nil { + return nil, fmt.Errorf("Error converting arg %d to GValue: %s", i, err.Error()) + } + C.val_list_insert(valv, C.int(i+1), val.native()) + } + + t := v.TypeFromInstance() + // TODO: use just the signal name + id := C.g_signal_lookup((*C.gchar)(cstr), C.GType(t)) + + ret, err := ValueAlloc() + if err != nil { + return nil, errors.New("Error creating Value for return value") + } + C.g_signal_emitv(valv, id, C.GQuark(0), ret.native()) + + return ret.GoValue() +} + +// HandlerBlock is a wrapper around g_signal_handler_block(). +func (v *Object) HandlerBlock(handle SignalHandle) { + C.g_signal_handler_block(C.gpointer(v.GObject), C.gulong(handle)) +} + +// HandlerUnblock is a wrapper around g_signal_handler_unblock(). +func (v *Object) HandlerUnblock(handle SignalHandle) { + C.g_signal_handler_unblock(C.gpointer(v.GObject), C.gulong(handle)) +} + +// HandlerDisconnect is a wrapper around g_signal_handler_disconnect(). +func (v *Object) HandlerDisconnect(handle SignalHandle) { + C.g_signal_handler_disconnect(C.gpointer(v.GObject), C.gulong(handle)) + C.g_closure_invalidate(signals[handle]) + delete(closures.m, signals[handle]) + delete(signals, handle) +} + +// Wrapper function for new objects with reference management. +func wrapObject(ptr unsafe.Pointer) *Object { + obj := &Object{ToGObject(ptr)} + + if obj.IsFloating() { + obj.RefSink() + } else { + obj.Ref() + } + + runtime.SetFinalizer(obj, (*Object).Unref) + return obj +} + +/* + * GInitiallyUnowned + */ + +// InitiallyUnowned is a representation of GLib's GInitiallyUnowned. +type InitiallyUnowned struct { + // This must be a pointer so copies of the ref-sinked object + // do not outlive the original object, causing an unref + // finalizer to prematurely run. + *Object +} + +// Native returns a pointer to the underlying GObject. This is implemented +// here rather than calling Native on the embedded Object to prevent a nil +// pointer dereference. +func (v *InitiallyUnowned) Native() uintptr { + if v == nil || v.Object == nil { + return uintptr(unsafe.Pointer(nil)) + } + return v.Object.Native() +} + +/* + * GValue + */ + +// Value is a representation of GLib's GValue. +// +// Don't allocate Values on the stack or heap manually as they may not +// be properly unset when going out of scope. Instead, use ValueAlloc(), +// which will set the runtime finalizer to unset the Value after it has +// left scope. +type Value struct { + GValue *C.GValue +} + +// native returns a pointer to the underlying GValue. +func (v *Value) native() *C.GValue { + return v.GValue +} + +// Native returns a pointer to the underlying GValue. +func (v *Value) Native() unsafe.Pointer { + return unsafe.Pointer(v.native()) +} + +// ValueAlloc allocates a Value and sets a runtime finalizer to call +// g_value_unset() on the underlying GValue after leaving scope. +// ValueAlloc() returns a non-nil error if the allocation failed. +func ValueAlloc() (*Value, error) { + c := C._g_value_alloc() + if c == nil { + return nil, errNilPtr + } + + v := &Value{c} + + //An allocated GValue is not guaranteed to hold a value that can be unset + //We need to double check before unsetting, to prevent: + //`g_value_unset: assertion 'G_IS_VALUE (value)' failed` + runtime.SetFinalizer(v, func(f *Value) { + if t, _, err := f.Type(); err != nil || t == TYPE_INVALID || t == TYPE_NONE { + C.g_free(C.gpointer(f.native())) + return + } + + f.unset() + }) + + return v, nil +} + +// ValueInit is a wrapper around g_value_init() and allocates and +// initializes a new Value with the Type t. A runtime finalizer is set +// to call g_value_unset() on the underlying GValue after leaving scope. +// ValueInit() returns a non-nil error if the allocation failed. +func ValueInit(t Type) (*Value, error) { + c := C._g_value_init(C.GType(t)) + if c == nil { + return nil, errNilPtr + } + + v := &Value{c} + + runtime.SetFinalizer(v, (*Value).unset) + return v, nil +} + +// ValueFromNative returns a type-asserted pointer to the Value. +func ValueFromNative(l unsafe.Pointer) *Value { + //TODO why it does not add finalizer to the value? + return &Value{(*C.GValue)(l)} +} + +func (v *Value) unset() { + C.g_value_unset(v.native()) +} + +// Type is a wrapper around the G_VALUE_HOLDS_GTYPE() macro and +// the g_value_get_gtype() function. GetType() returns TYPE_INVALID if v +// does not hold a Type, or otherwise returns the Type of v. +func (v *Value) Type() (actual Type, fundamental Type, err error) { + if !gobool(C._g_is_value(v.native())) { + return actual, fundamental, errors.New("invalid GValue") + } + cActual := C._g_value_type(v.native()) + cFundamental := C._g_value_fundamental(cActual) + return Type(cActual), Type(cFundamental), nil +} + +// GValue converts a Go type to a comparable GValue. GValue() +// returns a non-nil error if the conversion was unsuccessful. +func GValue(v interface{}) (gvalue *Value, err error) { + if v == nil { + val, err := ValueInit(TYPE_POINTER) + if err != nil { + return nil, err + } + val.SetPointer(uintptr(unsafe.Pointer(nil))) + return val, nil + } + + switch e := v.(type) { + case bool: + val, err := ValueInit(TYPE_BOOLEAN) + if err != nil { + return nil, err + } + val.SetBool(e) + return val, nil + + case int8: + val, err := ValueInit(TYPE_CHAR) + if err != nil { + return nil, err + } + val.SetSChar(e) + return val, nil + + case int64: + val, err := ValueInit(TYPE_INT64) + if err != nil { + return nil, err + } + val.SetInt64(e) + return val, nil + + case int: + val, err := ValueInit(TYPE_INT) + if err != nil { + return nil, err + } + val.SetInt(e) + return val, nil + + case uint8: + val, err := ValueInit(TYPE_UCHAR) + if err != nil { + return nil, err + } + val.SetUChar(e) + return val, nil + + case uint64: + val, err := ValueInit(TYPE_UINT64) + if err != nil { + return nil, err + } + val.SetUInt64(e) + return val, nil + + case uint: + val, err := ValueInit(TYPE_UINT) + if err != nil { + return nil, err + } + val.SetUInt(e) + return val, nil + + case float32: + val, err := ValueInit(TYPE_FLOAT) + if err != nil { + return nil, err + } + val.SetFloat(e) + return val, nil + + case float64: + val, err := ValueInit(TYPE_DOUBLE) + if err != nil { + return nil, err + } + val.SetDouble(e) + return val, nil + + case string: + val, err := ValueInit(TYPE_STRING) + if err != nil { + return nil, err + } + val.SetString(e) + return val, nil + + case *Object: + val, err := ValueInit(TYPE_OBJECT) + if err != nil { + return nil, err + } + val.SetInstance(uintptr(unsafe.Pointer(e.GObject))) + return val, nil + + default: + /* Try this since above doesn't catch constants under other types */ + rval := reflect.ValueOf(v) + switch rval.Kind() { + case reflect.Int8: + val, err := ValueInit(TYPE_CHAR) + if err != nil { + return nil, err + } + val.SetSChar(int8(rval.Int())) + return val, nil + + case reflect.Int16: + return nil, errors.New("Type not implemented") + + case reflect.Int32: + return nil, errors.New("Type not implemented") + + case reflect.Int64: + val, err := ValueInit(TYPE_INT64) + if err != nil { + return nil, err + } + val.SetInt64(rval.Int()) + return val, nil + + case reflect.Int: + val, err := ValueInit(TYPE_INT) + if err != nil { + return nil, err + } + val.SetInt(int(rval.Int())) + return val, nil + + case reflect.Uintptr, reflect.Ptr: + val, err := ValueInit(TYPE_POINTER) + if err != nil { + return nil, err + } + val.SetPointer(rval.Pointer()) + return val, nil + } + } + + return nil, errors.New("Type not implemented") +} + +// GValueMarshaler is a marshal function to convert a GValue into an +// appropriate Go type. The uintptr parameter is a *C.GValue. +type GValueMarshaler func(uintptr) (interface{}, error) + +// TypeMarshaler represents an actual type and it's associated marshaler. +type TypeMarshaler struct { + T Type + F GValueMarshaler +} + +// RegisterGValueMarshalers adds marshalers for several types to the +// internal marshalers map. Once registered, calling GoValue on any +// Value witha registered type will return the data returned by the +// marshaler. +func RegisterGValueMarshalers(tm []TypeMarshaler) { + gValueMarshalers.register(tm) +} + +type marshalMap map[Type]GValueMarshaler + +// gValueMarshalers is a map of Glib types to functions to marshal a +// GValue to a native Go type. +var gValueMarshalers = marshalMap{ + TYPE_INVALID: marshalInvalid, + TYPE_NONE: marshalNone, + TYPE_INTERFACE: marshalInterface, + TYPE_CHAR: marshalChar, + TYPE_UCHAR: marshalUchar, + TYPE_BOOLEAN: marshalBoolean, + TYPE_INT: marshalInt, + TYPE_LONG: marshalLong, + TYPE_ENUM: marshalEnum, + TYPE_INT64: marshalInt64, + TYPE_UINT: marshalUint, + TYPE_ULONG: marshalUlong, + TYPE_FLAGS: marshalFlags, + TYPE_UINT64: marshalUint64, + TYPE_FLOAT: marshalFloat, + TYPE_DOUBLE: marshalDouble, + TYPE_STRING: marshalString, + TYPE_POINTER: marshalPointer, + TYPE_BOXED: marshalBoxed, + TYPE_OBJECT: marshalObject, + TYPE_VARIANT: marshalVariant, +} + +func (m marshalMap) register(tm []TypeMarshaler) { + for i := range tm { + m[tm[i].T] = tm[i].F + } +} + +func (m marshalMap) lookup(v *Value) (GValueMarshaler, error) { + actual, fundamental, err := v.Type() + if err != nil { + return nil, err + } + + if f, ok := m[actual]; ok { + return f, nil + } + if f, ok := m[fundamental]; ok { + return f, nil + } + return nil, errors.New("missing marshaler for type") +} + +func marshalInvalid(uintptr) (interface{}, error) { + return nil, errors.New("invalid type") +} + +func marshalNone(uintptr) (interface{}, error) { + return nil, nil +} + +func marshalInterface(uintptr) (interface{}, error) { + return nil, errors.New("interface conversion not yet implemented") +} + +func marshalChar(p uintptr) (interface{}, error) { + c := C.g_value_get_schar((*C.GValue)(unsafe.Pointer(p))) + return int8(c), nil +} + +func marshalUchar(p uintptr) (interface{}, error) { + c := C.g_value_get_uchar((*C.GValue)(unsafe.Pointer(p))) + return uint8(c), nil +} + +func marshalBoolean(p uintptr) (interface{}, error) { + c := C.g_value_get_boolean((*C.GValue)(unsafe.Pointer(p))) + return gobool(c), nil +} + +func marshalInt(p uintptr) (interface{}, error) { + c := C.g_value_get_int((*C.GValue)(unsafe.Pointer(p))) + return int(c), nil +} + +func marshalLong(p uintptr) (interface{}, error) { + c := C.g_value_get_long((*C.GValue)(unsafe.Pointer(p))) + return int(c), nil +} + +func marshalEnum(p uintptr) (interface{}, error) { + c := C.g_value_get_enum((*C.GValue)(unsafe.Pointer(p))) + return int(c), nil +} + +func marshalInt64(p uintptr) (interface{}, error) { + c := C.g_value_get_int64((*C.GValue)(unsafe.Pointer(p))) + return int64(c), nil +} + +func marshalUint(p uintptr) (interface{}, error) { + c := C.g_value_get_uint((*C.GValue)(unsafe.Pointer(p))) + return uint(c), nil +} + +func marshalUlong(p uintptr) (interface{}, error) { + c := C.g_value_get_ulong((*C.GValue)(unsafe.Pointer(p))) + return uint(c), nil +} + +func marshalFlags(p uintptr) (interface{}, error) { + c := C.g_value_get_flags((*C.GValue)(unsafe.Pointer(p))) + return uint(c), nil +} + +func marshalUint64(p uintptr) (interface{}, error) { + c := C.g_value_get_uint64((*C.GValue)(unsafe.Pointer(p))) + return uint64(c), nil +} + +func marshalFloat(p uintptr) (interface{}, error) { + c := C.g_value_get_float((*C.GValue)(unsafe.Pointer(p))) + return float32(c), nil +} + +func marshalDouble(p uintptr) (interface{}, error) { + c := C.g_value_get_double((*C.GValue)(unsafe.Pointer(p))) + return float64(c), nil +} + +func marshalString(p uintptr) (interface{}, error) { + c := C.g_value_get_string((*C.GValue)(unsafe.Pointer(p))) + return C.GoString((*C.char)(c)), nil +} + +func marshalBoxed(p uintptr) (interface{}, error) { + c := C.g_value_get_boxed((*C.GValue)(unsafe.Pointer(p))) + return uintptr(unsafe.Pointer(c)), nil +} + +func marshalPointer(p uintptr) (interface{}, error) { + c := C.g_value_get_pointer((*C.GValue)(unsafe.Pointer(p))) + return unsafe.Pointer(c), nil +} + +func marshalObject(p uintptr) (interface{}, error) { + c := C.g_value_get_object((*C.GValue)(unsafe.Pointer(p))) + return newObject((*C.GObject)(c)), nil +} + +func marshalVariant(p uintptr) (interface{}, error) { + return nil, errors.New("variant conversion not yet implemented") +} + +// GoValue converts a Value to comparable Go type. GoValue() +// returns a non-nil error if the conversion was unsuccessful. The +// returned interface{} must be type asserted as the actual Go +// representation of the Value. +// +// This function is a wrapper around the many g_value_get_*() +// functions, depending on the type of the Value. +func (v *Value) GoValue() (interface{}, error) { + f, err := gValueMarshalers.lookup(v) + if err != nil { + return nil, err + } + + //No need to add finalizer because it is already done by ValueAlloc and ValueInit + rv, err := f(uintptr(unsafe.Pointer(v.native()))) + return rv, err +} + +// SetBool is a wrapper around g_value_set_boolean(). +func (v *Value) SetBool(val bool) { + C.g_value_set_boolean(v.native(), gbool(val)) +} + +// SetSChar is a wrapper around g_value_set_schar(). +func (v *Value) SetSChar(val int8) { + C.g_value_set_schar(v.native(), C.gint8(val)) +} + +// SetInt64 is a wrapper around g_value_set_int64(). +func (v *Value) SetInt64(val int64) { + C.g_value_set_int64(v.native(), C.gint64(val)) +} + +// SetInt is a wrapper around g_value_set_int(). +func (v *Value) SetInt(val int) { + C.g_value_set_int(v.native(), C.gint(val)) +} + +// SetUChar is a wrapper around g_value_set_uchar(). +func (v *Value) SetUChar(val uint8) { + C.g_value_set_uchar(v.native(), C.guchar(val)) +} + +// SetUInt64 is a wrapper around g_value_set_uint64(). +func (v *Value) SetUInt64(val uint64) { + C.g_value_set_uint64(v.native(), C.guint64(val)) +} + +// SetUInt is a wrapper around g_value_set_uint(). +func (v *Value) SetUInt(val uint) { + C.g_value_set_uint(v.native(), C.guint(val)) +} + +// SetFloat is a wrapper around g_value_set_float(). +func (v *Value) SetFloat(val float32) { + C.g_value_set_float(v.native(), C.gfloat(val)) +} + +// SetDouble is a wrapper around g_value_set_double(). +func (v *Value) SetDouble(val float64) { + C.g_value_set_double(v.native(), C.gdouble(val)) +} + +// SetString is a wrapper around g_value_set_string(). +func (v *Value) SetString(val string) { + cstr := C.CString(val) + defer C.free(unsafe.Pointer(cstr)) + C.g_value_set_string(v.native(), (*C.gchar)(cstr)) +} + +// SetInstance is a wrapper around g_value_set_instance(). +func (v *Value) SetInstance(instance uintptr) { + C.g_value_set_instance(v.native(), C.gpointer(instance)) +} + +// SetPointer is a wrapper around g_value_set_pointer(). +func (v *Value) SetPointer(p uintptr) { + C.g_value_set_pointer(v.native(), C.gpointer(p)) +} + +// GetPointer is a wrapper around g_value_get_pointer(). +func (v *Value) GetPointer() unsafe.Pointer { + return unsafe.Pointer(C.g_value_get_pointer(v.native())) +} + +// GetString is a wrapper around g_value_get_string(). GetString() +// returns a non-nil error if g_value_get_string() returned a NULL +// pointer to distinguish between returning a NULL pointer and returning +// an empty string. +func (v *Value) GetString() (string, error) { + c := C.g_value_get_string(v.native()) + if c == nil { + return "", errNilPtr + } + return C.GoString((*C.char)(c)), nil +} + +type Signal struct { + name string + signalId C.guint +} + +func SignalNew(s string) (*Signal, error) { + cstr := C.CString(s) + defer C.free(unsafe.Pointer(cstr)) + + signalId := C._g_signal_new((*C.gchar)(cstr)) + + if signalId == 0 { + return nil, fmt.Errorf("invalid signal name: %s", s) + } + + return &Signal{ + name: s, + signalId: signalId, + }, nil +} + +func (s *Signal) String() string { + return s.name +} + +type Quark uint32 + +// GetApplicationName is a wrapper around g_get_application_name(). +func GetApplicationName() string { + c := C.g_get_application_name() + + return C.GoString((*C.char)(c)) +} + +// SetApplicationName is a wrapper around g_set_application_name(). +func SetApplicationName(name string) { + cstr := (*C.gchar)(C.CString(name)) + defer C.free(unsafe.Pointer(cstr)) + + C.g_set_application_name(cstr) +} + +// InitI18n initializes the i18n subsystem. +func InitI18n(domain string, dir string) { + domainStr := C.CString(domain) + defer C.free(unsafe.Pointer(domainStr)) + + dirStr := C.CString(dir) + defer C.free(unsafe.Pointer(dirStr)) + + C.init_i18n(domainStr, dirStr) +} + +// Local localizes a string using gettext +func Local(input string) string { + cstr := C.CString(input) + defer C.free(unsafe.Pointer(cstr)) + + return C.GoString(C.localize(cstr)) +} |