libGimbal 0.1.0
C17-Based Extended Standard Library and Cross-Language Runtime Framework
Loading...
Searching...
No Matches
Collaboration diagram for Signals:

Files

file  gimbal_c_closure.h
 
file  gimbal_class_closure.h
 
file  gimbal_closure.h
 
file  gimbal_marshal.h
 
file  gimbal_signal.h
 
file  gimbal_signal_closure.h
 

Data Structures

struct  GblCClosure
 
struct  GblClassClosure
 
struct  GblClosure
 
struct  GblSignalClosure
 

Typedefs

typedef GBL_RESULT(* GblMarshalFn) (GblClosure *pClosure, GblVariant *pRetValue, size_t argCount, GblVariant *pArgs, GblPtr pMarshalData)
 

Detailed Description

Signal emission mechanism and its types and API.

Overview

libGimbal's signal system implements a powerful cross-language event callback mechanism which decouples event emitting types from those types which receive or listen for events. It is based upon both GTk's "signals" and Qt's "signals and slots" and is expecially powerful for GUI/widget programming.

Declaration

It is a good practice to use DSL macros to predeclare any signals which are associated with a GblType as part of their public API declaration within their respective header file. As an example, the signals associated with the GblOptionGroup are declared by:

(parsePrePass, (GBL_POINTER_TYPE, stringList),
(parsePostPass, (GBL_POINTER_TYPE, stringList),
(parseError, (GBL_ENUM_TYPE, errorCode)
)
#define GBL_ENUM_TYPE
Type UUID of GblEnumClass.
Definition gimbal_enum.h:22
#define GBL_SIGNALS(instanceStruct,...)
Declares a list of signals to be associated with the given instanceStruct.
Grouping of command-line options.

This declares GblOptionGroup as being able to emit 3 different signals, with parsePrePass and parsePostPass sending pointers to GblStringList as their parameters, and parseError passing along an error code as a GblEnum as its parameter.

Registration

The first thing that must happen before signals can be used is that they get registered at runtime with an actual type. This is typically done within the GblTypeInfo::pFnClassInit routine for a given type, only when its reference count is 0, meaning it is being instantiated for the first time:

static GBL_RESULT GblOptionGroupClass_init_(GblClass* pClass, const void* pData) {
// ...
}
#define GBL_OPTION_GROUP_TYPE
Type UUID for GblOptionGroup.
GBL_RESULT
#define GBL_SIGNALS_REGISTER(instanceStruct,...)
Registers the list of signals which has been associated with the given instanceStruct.
GblRefCount GblType_classRefCount(GblType self)
Returns the reference counter for the given GblType's internally-managed default GblClass.
Base struct for all type classes.

Basic Usage

In order to get notified when a signal gets fired from a particular GblInstance subtype, we must first connect a closure to it, so that it can be invoked later when the signal fires. The simplest way is to use a C function pointer as the callback:

// C callback to be called when a GblOptionGroupClass::parseError signal is fired.
static void GblOptionGroup_onParseError_(GblInstance* pReciever, GblEnum error) {
// Retrieve our emission counter from the associated closure's userdata pointer.
size_t* pEmittedCounter = (size_t*)GblClosure_currentUserdata();
// Increment our counter.
*pEmittedCounter++;
// Retrieve a pointer to the instance that emitted the current signal.
GBL_LOG_ERROR("signal_test", "%s emitted parseError %u to %s!",
GblObject_name(GBL_OBJECT(pEmitter)),
error,
GblObject_name(GBL_OBJECT(pReceiver)));
}
int main(int argc, const char* argv[]) {
// Create the emitting object.
GblOptionGroup* pSender = GBL_NEW(GblOptionGroupClass, "name", "emitter");
// Create the receiving object.
GblObject* pReceiver = GBL_NEW(GblObject, "name", "recipient");
// Counter for number of times signal was emitted
size_t emittedCounter = 0;
// Connect the receiver's callback to the emitter's signal, plus give it a counter pointer.
GBL_CONNECT(pSender,
"parseError",
pReceiver,
GblOptionGroup_onParseError_,
&emittedCounter);
// Manually fire the signal ourselves (usually done internally)
GBL_EMIT(pSender, "parseError", GBL_RESULT_ERROR_INVALID_TYPE);
// Counter should've been incremented from the signal handler!
GBL_ASSERT(emittedCounter == 1);
return 0;
}
void * GblClosure_currentUserdata(void)
Returns a pointer to the userdatea of the inner-most currently executing GblClosure instance.
#define GBL_LOG_ERROR(domain,...)
Writes to log with GBL_LOG_ERROR.
#define GBL_NEW(...)
DSL macro used to heap-construct a GblObject-derived type.
#define GBL_OBJECT(self)
Casts a GblInstance to a GblObject.
#define GBL_CONNECT(...)
Connects the signal with the given name from the given emitter to a receiver with the given callback ...
#define GBL_EMIT(emitter,...)
Emits a signal from the given emitter with the given name and arguments.
GblInstance * GblSignal_emitter(void)
Returns a pointer to the GblInstance which emitted the acive signal or NULL if there isn't an active ...
uint32_t GblEnum
Standard-sized enum type, 32-bits across platforms.
Base struct for all instantiable meta types.
Main Object-Oriented Instance with Properties, EventReceivers, and Parenting.
GblClass structure for GblOptionGroup.

Typedef Documentation

◆ GblMarshalFn

typedef GBL_RESULT(* GblMarshalFn) (GblClosure *pClosure, GblVariant *pRetValue, size_t argCount, GblVariant *pArgs, GblPtr pMarshalData)

#include <gimbal_marshal.h>

Function signature for a generic marshal function.

Marshal functions form the basis of the closure system, and are used by all GblClosure instances. They are the primary entry point for generic function invocation, and are the glue between a generic GblClosure and an actual language-dependent real function call.

They take a generic list of arguments, marshal them into an actual function (which is typically stored with GblClosure), then demarshal out the return type.

Definition at line 50 of file gimbal_marshal.h.