Skip to content

rework signal registering #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
strategy:
matrix:
os:
- ubuntu-latest
- ubuntu-22.04
- windows-latest
- macos-latest
runs-on: ${{ matrix.os }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 0 additions & 25 deletions glib/glib.go
Original file line number Diff line number Diff line change
Expand Up @@ -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().
Expand Down
6 changes: 0 additions & 6 deletions glib/glib.go.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions glib/gobjectclass.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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) {
Expand Down
136 changes: 136 additions & 0 deletions glib/gsignal.go
Original file line number Diff line number Diff line change
@@ -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
}
30 changes: 30 additions & 0 deletions glib/gsignal_exports.go
Original file line number Diff line number Diff line change
@@ -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)),
))
}
Loading