diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..3bc33dd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Use go-gst issue tracker + url: https://github.com/go-gst/go-gst/issues + about: Use the go-gst issue tracker for issues with go-glib please. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0af981d..b95b1d7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: os: - - ubuntu-latest + - ubuntu-22.04 - windows-latest - macos-latest runs-on: ${{ matrix.os }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bb5edad..1ccdcf1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,7 +8,7 @@ on: jobs: setup: name: Tests on codebase - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Setup GStreamer id: setup_gstreamer diff --git a/glib/glib.go b/glib/glib.go index 295d5d0..77debcf 100644 --- a/glib/glib.go +++ b/glib/glib.go @@ -458,31 +458,6 @@ func (v *InitiallyUnowned) Native() unsafe.Pointer { return v.Object.Native() } -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(). diff --git a/glib/glib.go.h b/glib/glib.go.h index 1b363e7..f92deef 100644 --- a/glib/glib.go.h +++ b/glib/glib.go.h @@ -157,12 +157,6 @@ static GClosure *_g_closure_new(gpointer handle) return (closure); } -static inline guint _g_signal_new(const gchar *name) { - return g_signal_new(name, G_TYPE_OBJECT, G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, - 0, NULL, NULL, g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 0); -} - static void init_i18n(const char *domain, const char *dir) { setlocale(LC_ALL, ""); bindtextdomain(domain, dir); diff --git a/glib/gobjectclass.go b/glib/gobjectclass.go index 6244f2d..9d3e050 100644 --- a/glib/gobjectclass.go +++ b/glib/gobjectclass.go @@ -4,6 +4,7 @@ package glib #include "glib.go.h" GObjectClass * toGObjectClass (void *p) { return (G_OBJECT_CLASS(p)); } +GType typeFromGObjectClass (GObjectClass *c) { return (G_OBJECT_CLASS_TYPE(c)); } */ import "C" @@ -25,6 +26,11 @@ func (o *ObjectClass) Unsafe() unsafe.Pointer { return unsafe.Pointer(o.ptr) } // Instance returns the underlying C GObjectClass pointer func (o *ObjectClass) Instance() *C.GObjectClass { return o.ptr } +// Instance returns the underlying C GObjectClass pointer +func (o *ObjectClass) Type() Type { + return Type(C.typeFromGObjectClass(o.ptr)) +} + // InstallProperties will install the given ParameterSpecs to the object class. // They will be IDed in the order they are provided. func (o *ObjectClass) InstallProperties(params []*ParamSpec) { diff --git a/glib/gsignal.go b/glib/gsignal.go new file mode 100644 index 0000000..1eecc6e --- /dev/null +++ b/glib/gsignal.go @@ -0,0 +1,136 @@ +package glib + +/* +#include "glib.go.h" + +extern gboolean goSignalAccumulator (GSignalInvocationHint* ihint, GValue* return_accu, const GValue* handler_return, gpointer data); +gboolean cgoSignalAccumulator (GSignalInvocationHint* ihint, GValue* return_accu, const GValue* handler_return, gpointer data) { + return goSignalAccumulator(ihint, return_accu, handler_return, data); +} +*/ +import "C" +import ( + "unsafe" + + gopointer "github.com/go-gst/go-pointer" +) + +// SignalFlags are used to specify a signal's behavior. +type SignalFlags C.GSignalFlags + +const ( + // SignalRunFirst: Invoke the object method handler in the first emission stage. + SignalRunFirst SignalFlags = C.G_SIGNAL_RUN_FIRST + // SignalRunLast: Invoke the object method handler in the third emission stage. + SignalRunLast SignalFlags = C.G_SIGNAL_RUN_LAST + // SignalRunCleanup: Invoke the object method handler in the last emission stage. + SignalRunCleanup SignalFlags = C.G_SIGNAL_RUN_CLEANUP + // SignalNoRecurse: Signals being emitted for an object while currently being in + // emission for this very object will not be emitted recursively, + // but instead cause the first emission to be restarted. + SignalNoRecurse SignalFlags = C.G_SIGNAL_NO_RECURSE + // SignalDetailed: This signal supports "::detail" appendices to the signal name + // upon handler connections and emissions. + SignalDetailed SignalFlags = C.G_SIGNAL_DETAILED + // SignalAction: Action signals are signals that may freely be emitted on alive + // objects from user code via g_signal_emit() and friends, without + // the need of being embedded into extra code that performs pre or + // post emission adjustments on the object. They can also be thought + // of as object methods which can be called generically by + // third-party code. + SignalAction SignalFlags = C.G_SIGNAL_ACTION + // SignalNoHooks: No emissions hooks are supported for this signal. + SignalNoHooks SignalFlags = C.G_SIGNAL_NO_HOOKS + // SignalMustCollect: Varargs signal emission will always collect the + // arguments, even if there are no signal handlers connected. Since 2.30. + SignalMustCollect SignalFlags = C.G_SIGNAL_MUST_COLLECT + // SignalDeprecated: The signal is deprecated and will be removed + // in a future version. A warning will be generated if it is connected while + // running with G_ENABLE_DIAGNOSTIC=1. Since 2.32. + SignalDeprecated SignalFlags = C.G_SIGNAL_DEPRECATED + // SignalAccumulatorFirstRun: Only used in #GSignalAccumulator accumulator + // functions for the #GSignalInvocationHint::run_type field to mark the first + // call to the accumulator function for a signal emission. Since 2.68. + SignalAccumulatorFirstRun SignalFlags = C.G_SIGNAL_ACCUMULATOR_FIRST_RUN +) + +type SignalInvocationHint struct { + native *C.GSignalInvocationHint +} + +func (s *SignalInvocationHint) SignalID() uint { + return uint(s.native.signal_id) +} + +func (s *SignalInvocationHint) Detail() Quark { + return Quark(s.native.detail) +} + +func (s *SignalInvocationHint) RunType() SignalFlags { + return SignalFlags(s.native.run_type) +} + +// SignalAccumulator is a special callback function that can be used to collect return values of the various callbacks that are called during a signal emission. +type SignalAccumulator func(ihint *SignalInvocationHint, return_accu *Value, handler_return *Value) bool + +type Signal struct { + name string + signalId C.guint +} + +// NewSignal Creates a new signal. (This is usually done in the class initializer.) this is a wrapper around g_signal_newv +func NewSignal( + name string, + _type Type, + flags SignalFlags, + handler any, + accumulator SignalAccumulator, + param_types []Type, + return_type Type, +) (*Signal, error) { + cname := C.CString(name) + defer C.free(unsafe.Pointer(cname)) + + cparams := make([]C.GType, 0, len(param_types)) + + for _, t := range param_types { + cparams = append(cparams, C.GType(t)) + } + + var err error + var classHandler *C.GClosure + + if handler != nil { + classHandler, err = ClosureNew(handler) + + if err != nil { + return nil, err + } + + defer C.g_closure_unref(classHandler) + } + + var accudata C.gpointer + var cAccumulator C.GSignalAccumulator + + if accumulator != nil { + accudata = C.gpointer(gopointer.Save(accumulator)) + + cAccumulator = C.GSignalAccumulator(C.cgoSignalAccumulator) + } + + signalID := C.g_signal_newv( + cname, + C.GType(_type), + C.GSignalFlags(flags), + classHandler, + cAccumulator, + accudata, + nil, // no marshaller needed + C.GType(return_type), + C.uint(len(cparams)), + unsafe.SliceData(cparams), + ) + + return &Signal{name: name, signalId: signalID}, nil +} diff --git a/glib/gsignal_exports.go b/glib/gsignal_exports.go new file mode 100644 index 0000000..3ca59c8 --- /dev/null +++ b/glib/gsignal_exports.go @@ -0,0 +1,30 @@ +package glib + +/* +#cgo CFLAGS: -Wno-deprecated-declarations +#include "glib.go.h" +*/ +import "C" +import ( + "unsafe" + + gopointer "github.com/go-gst/go-pointer" +) + +//export goSignalAccumulator +func goSignalAccumulator( + ihint *C.GSignalInvocationHint, + return_accu *C.GValue, + handler_return *C.GValue, + data C.gpointer, +) C.gboolean { + goAccuI := gopointer.Restore(unsafe.Pointer(data)) + + goAccu := goAccuI.(SignalAccumulator) + + return gbool(goAccu( + &SignalInvocationHint{ihint}, + ValueFromNative(unsafe.Pointer(return_accu)), + ValueFromNative(unsafe.Pointer(handler_return)), + )) +}