Simplify and extend callback/signalling system

- Signals and dynamic callbacks now require declarations to be made
  before being used.  What this does is allows us to get information
  about the functions dynamically which can be relayed to the user and
  plugins for future extended usage (this should have big implications
  later for scripting in particular, hopefully).

- Reduced the number of types calldata uses from "everything I could
  think of" to simply integer, float, bool, pointer/object, string.
  Integer data is now stored as long long.  Floats are now stored as
  doubles (check em).

- Use a more consistent naming scheme for lexer error/warning macros.

- Fixed a rather nasty bug where switching to an existing scene would
  cause it to increment sourceSceneRefs, which would mean that it would
  never end up never properly removing the source when the user clicks
  removed (stayed in limbo, obs_source_remove never got called)
This commit is contained in:
jp9000 2014-03-01 05:54:55 -07:00
parent e560a426c5
commit e9342143a7
21 changed files with 531 additions and 419 deletions

View file

@ -58,10 +58,12 @@ endif()
set(libobs_callback_SOURCES
callback/calldata.c
callback/decl.c
callback/signal.c
callback/proc.c)
set(libobs_callback_HEADERS
callback/calldata.h
callback/decl.h
callback/proc.h
callback/signal.h)

View file

@ -22,7 +22,7 @@
/*
* Uses a data stack. Probably more complex than it should be, but reduces
* cache fetching.
* fetching.
*
* Stack format is:
* [size_t param1_name_size]

View file

@ -31,6 +31,18 @@ extern "C" {
* procedures, and callbacks.
*/
enum call_param_type {
CALL_PARAM_TYPE_VOID,
CALL_PARAM_TYPE_INT,
CALL_PARAM_TYPE_FLOAT,
CALL_PARAM_TYPE_BOOL,
CALL_PARAM_TYPE_PTR,
CALL_PARAM_TYPE_STRING
};
#define CALL_PARAM_IN (1<<0)
#define CALL_PARAM_OUT (1<<1)
struct calldata {
size_t size; /* size of the stack, in bytes */
size_t capacity; /* capacity of the stack, in bytes */
@ -49,9 +61,6 @@ static inline void calldata_free(struct calldata *data)
bfree(data->stack);
}
/* NOTE: 'get' functions return true only if paramter exists, and is the
* same size. They return false otherwise. */
EXPORT bool calldata_getdata(calldata_t data, const char *name, void *out,
size_t size);
EXPORT void calldata_setdata(calldata_t data, const char *name, const void *in,
@ -65,109 +74,17 @@ static inline void calldata_clear(struct calldata *data)
}
}
static inline bool calldata_getchar (calldata_t data, const char *name,
char *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
/* ------------------------------------------------------------------------- */
/* NOTE: 'get' functions return true only if paramter exists, and is the
* same type. They return false otherwise. */
static inline bool calldata_getuchar (calldata_t data, const char *name,
unsigned char *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getshort (calldata_t data, const char *name,
short *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getushort(calldata_t data, const char *name,
unsigned short *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getint (calldata_t data, const char *name,
int *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getuint (calldata_t data, const char *name,
unsigned int *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getlong (calldata_t data, const char *name,
long *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getulong (calldata_t data, const char *name,
unsigned long *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getint8 (calldata_t data, const char *name,
int8_t *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getuint8 (calldata_t data, const char *name,
uint8_t *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getint16 (calldata_t data, const char *name,
int8_t *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getuint16(calldata_t data, const char *name,
uint8_t *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getint32 (calldata_t data, const char *name,
int32_t *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getuint32(calldata_t data, const char *name,
uint32_t *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getint64 (calldata_t data, const char *name,
int64_t *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getuint64(calldata_t data, const char *name,
uint64_t *val)
static inline bool calldata_getint(calldata_t data, const char *name,
long long *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getfloat (calldata_t data, const char *name,
float *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getdouble(calldata_t data, const char *name,
double *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
@ -179,12 +96,6 @@ static inline bool calldata_getbool (calldata_t data, const char *name,
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getsize (calldata_t data, const char *name,
size_t *val)
{
return calldata_getdata(data, name, val, sizeof(*val));
}
static inline bool calldata_getptr (calldata_t data, const char *name,
void *p_ptr)
{
@ -195,147 +106,29 @@ EXPORT bool calldata_getstring(calldata_t data, const char *name,
const char **str);
/* ------------------------------------------------------------------------- */
/* call if you know your data is valid */
static inline char calldata_char(calldata_t data, const char *name)
static inline long long calldata_int(calldata_t data, const char *name)
{
char val;
calldata_getchar(data, name, &val);
return val;
}
static inline unsigned char calldata_uchar(calldata_t data, const char *name)
{
unsigned char val;
calldata_getuchar(data, name, &val);
return val;
}
static inline short calldata_short(calldata_t data, const char *name)
{
short val;
calldata_getshort(data, name, &val);
return val;
}
static inline unsigned short calldata_ushort(calldata_t data, const char *name)
{
unsigned short val;
calldata_getushort(data, name, &val);
return val;
}
static inline int calldata_int(calldata_t data, const char *name)
{
int val;
long long val = 0;
calldata_getint(data, name, &val);
return val;
}
static inline unsigned int calldata_uint(calldata_t data, const char *name)
static inline double calldata_float(calldata_t data, const char *name)
{
unsigned int val;
calldata_getuint(data, name, &val);
return val;
}
static inline long calldata_long(calldata_t data, const char *name)
{
long val;
calldata_getlong(data, name, &val);
return val;
}
static inline unsigned long calldata_ulong(calldata_t data, const char *name)
{
unsigned long val;
calldata_getulong(data, name, &val);
return val;
}
static inline int8_t calldata_int8(calldata_t data, const char *name)
{
int8_t val;
calldata_getint8(data, name, &val);
return val;
}
static inline uint8_t calldata_uint8(calldata_t data, const char *name)
{
uint8_t val;
calldata_getuint8(data, name, &val);
return val;
}
static inline int8_t calldata_int16(calldata_t data, const char *name)
{
int8_t val;
calldata_getint16(data, name, &val);
return val;
}
static inline uint8_t calldata_uint16(calldata_t data, const char *name)
{
uint8_t val;
calldata_getuint16(data, name, &val);
return val;
}
static inline int32_t calldata_int32(calldata_t data, const char *name)
{
int32_t val;
calldata_getint32(data, name, &val);
return val;
}
static inline uint32_t calldata_uint32(calldata_t data, const char *name)
{
uint32_t val;
calldata_getuint32(data, name, &val);
return val;
}
static inline int64_t calldata_int64(calldata_t data, const char *name)
{
int64_t val;
calldata_getint64(data, name, &val);
return val;
}
static inline uint64_t calldata_uint64(calldata_t data, const char *name)
{
uint64_t val;
calldata_getuint64(data, name, &val);
return val;
}
static inline float calldata_float(calldata_t data, const char *name)
{
float val;
double val = 0.0;
calldata_getfloat(data, name, &val);
return val;
}
static inline double calldata_double(calldata_t data, const char *name)
{
double val;
calldata_getdouble(data, name, &val);
return val;
}
static inline bool calldata_bool(calldata_t data, const char *name)
{
bool val;
bool val = false;
calldata_getbool(data, name, &val);
return val;
}
static inline size_t calldata_size(calldata_t data, const char *name)
{
size_t val;
calldata_getsize(data, name, &val);
return val;
}
static inline void *calldata_ptr(calldata_t data, const char *name)
{
void *val;
@ -352,108 +145,13 @@ static inline const char *calldata_string(calldata_t data, const char *name)
/* ------------------------------------------------------------------------- */
static void calldata_setchar (calldata_t data, const char *name, char val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setuchar (calldata_t data, const char *name,
unsigned char val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setshort (calldata_t data, const char *name,
short val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setushort(calldata_t data, const char *name,
unsigned short val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setint (calldata_t data, const char *name,
int val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setuint (calldata_t data, const char *name,
unsigned int val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setlong (calldata_t data, const char *name,
long val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setulong (calldata_t data, const char *name,
unsigned long val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setint8 (calldata_t data, const char *name,
int8_t val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setuint8 (calldata_t data, const char *name,
uint8_t val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setint16 (calldata_t data, const char *name,
int8_t val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setuint16(calldata_t data, const char *name,
uint8_t val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setint32 (calldata_t data, const char *name,
int32_t val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setuint32(calldata_t data, const char *name,
uint32_t val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setint64 (calldata_t data, const char *name,
int64_t val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setuint64(calldata_t data, const char *name,
uint64_t val)
long long val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setfloat (calldata_t data, const char *name,
float val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setdouble(calldata_t data, const char *name,
double val)
{
calldata_setdata(data, name, &val, sizeof(val));
@ -465,12 +163,6 @@ static inline void calldata_setbool (calldata_t data, const char *name,
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setsize (calldata_t data, const char *name,
size_t val)
{
calldata_setdata(data, name, &val, sizeof(val));
}
static inline void calldata_setptr (calldata_t data, const char *name,
void *ptr)
{

219
libobs/callback/decl.c Normal file
View file

@ -0,0 +1,219 @@
/*
* Copyright (c) 2014 Hugh Bailey <obs.jim@gmail.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.
*/
#include "../util/cf-parser.h"
#include "decl.h"
static inline void err_specifier_exists(struct cf_parser *cfp,
const char *storage)
{
cf_adderror(cfp, "'$1' specifier already exists", LEX_WARNING,
storage, NULL, NULL);
}
static inline void err_reserved_name(struct cf_parser *cfp, const char *name)
{
cf_adderror(cfp, "'$1' is a reserved name", LEX_ERROR,
name, NULL, NULL);
}
static bool is_in_out_specifier(struct cf_parser *cfp, struct strref *name,
uint32_t *type)
{
if (strref_cmp(name, "in") == 0) {
if (*type & CALL_PARAM_IN)
err_specifier_exists(cfp, "in");
*type |= CALL_PARAM_IN;
} else if (strref_cmp(name, "out") == 0) {
if (*type & CALL_PARAM_OUT)
err_specifier_exists(cfp, "out");
*type |= CALL_PARAM_OUT;
} else {
return false;
}
return true;
}
#define TYPE_OR_STORAGE "type or storage specifier"
static bool get_type(struct strref *ref, enum call_param_type *type,
bool is_return)
{
if (strref_cmp(ref, "int") == 0)
*type = CALL_PARAM_TYPE_INT;
else if (strref_cmp(ref, "float") == 0)
*type = CALL_PARAM_TYPE_FLOAT;
else if (strref_cmp(ref, "bool") == 0)
*type = CALL_PARAM_TYPE_BOOL;
else if (strref_cmp(ref, "ptr") == 0)
*type = CALL_PARAM_TYPE_PTR;
else if (strref_cmp(ref, "string") == 0)
*type = CALL_PARAM_TYPE_STRING;
else if (is_return && strref_cmp(ref, "void") == 0)
*type = CALL_PARAM_TYPE_VOID;
else
return false;
return true;
}
static bool is_reserved_name(const char *str)
{
return (strcmp(str, "int") == 0) ||
(strcmp(str, "float") == 0) ||
(strcmp(str, "bool") == 0) ||
(strcmp(str, "ptr") == 0) ||
(strcmp(str, "string") == 0) ||
(strcmp(str, "void") == 0) ||
(strcmp(str, "return") == 0);
}
static int parse_param(struct cf_parser *cfp, struct decl_info *decl)
{
struct strref ref;
int code;
struct decl_param param = {0};
/* get stprage specifiers */
code = cf_next_name_ref(cfp, &ref, TYPE_OR_STORAGE, ",");
if (code != PARSE_SUCCESS)
return code;
while (is_in_out_specifier(cfp, &ref, &param.flags)) {
code = cf_next_name_ref(cfp, &ref, TYPE_OR_STORAGE, ",");
if (code != PARSE_SUCCESS)
return code;
}
/* parameters not marked with specifers are input parameters */
if (param.flags == 0)
param.flags = CALL_PARAM_IN;
if (!get_type(&ref, &param.type, false)) {
cf_adderror_expecting(cfp, "type");
cf_go_to_token(cfp, ",", ")");
return PARSE_CONTINUE;
}
/* name */
code = cf_next_name(cfp, &param.name, "parameter name", ",");
if (code != PARSE_SUCCESS)
return code;
if (is_reserved_name(param.name))
err_reserved_name(cfp, param.name);
da_push_back(decl->params, &param);
return PARSE_SUCCESS;
}
static void parse_params(struct cf_parser *cfp, struct decl_info *decl)
{
struct cf_token peek;
int code;
if (!cf_peek_valid_token(cfp, &peek))
return;
while (peek.type == CFTOKEN_NAME) {
code = parse_param(cfp, decl);
if (code == PARSE_EOF)
return;
if (code != PARSE_CONTINUE && !cf_next_valid_token(cfp))
return;
if (cf_token_is(cfp, ")"))
break;
else if (cf_token_should_be(cfp, ",", ",", NULL) == PARSE_EOF)
return;
if (!cf_peek_valid_token(cfp, &peek))
return;
}
if (!cf_token_is(cfp, ")"))
cf_next_token_should_be(cfp, ")", NULL, NULL);
}
static void print_errors(struct cf_parser *cfp, const char *decl_string)
{
char *errors = error_data_buildstring(&cfp->error_list);
if (errors) {
blog(LOG_WARNING, "Errors/warnings for '%s':\n\n%s",
decl_string, errors);
bfree(errors);
}
}
bool parse_decl_string(struct decl_info *decl, const char *decl_string)
{
struct cf_parser cfp;
struct strref ret_type;
struct decl_param ret_param = {0};
int code;
bool success;
decl->decl_string = decl_string;
ret_param.flags = CALL_PARAM_OUT;
cf_parser_init(&cfp);
if (!cf_parser_parse(&cfp, decl_string, "declaraion"))
goto fail;
code = cf_get_name_ref(&cfp, &ret_type, "return type", NULL);
if (code == PARSE_EOF)
goto fail;
if (!get_type(&ret_type, &ret_param.type, true))
cf_adderror_expecting(&cfp, "return type");
code = cf_next_name(&cfp, &decl->name, "function name", "(");
if (code == PARSE_EOF)
goto fail;
if (is_reserved_name(decl->name))
err_reserved_name(&cfp, decl->name);
code = cf_next_token_should_be(&cfp, "(", "(", NULL);
if (code == PARSE_EOF)
goto fail;
parse_params(&cfp, decl);
fail:
success = !error_data_has_errors(&cfp.error_list);
if (success && ret_param.type != CALL_PARAM_TYPE_VOID) {
ret_param.name = bstrdup("return");
da_push_back(decl->params, &ret_param);
}
if (!success)
decl_info_free(decl);
print_errors(&cfp, decl_string);
cf_parser_free(&cfp);
return success;
}

61
libobs/callback/decl.h Normal file
View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2014 Hugh Bailey <obs.jim@gmail.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.
*/
#pragma once
#include "calldata.h"
#include "../util/darray.h"
#ifdef __cplusplus
extern "C" {
#endif
struct decl_param {
char *name;
enum call_param_type type;
uint32_t flags;
};
static inline void decl_param_free(struct decl_param *param)
{
if (param)
bfree(param->name);
memset(param, 0, sizeof(struct decl_param));
}
struct decl_info {
char *name;
const char *decl_string;
DARRAY(struct decl_param) params;
};
static inline void decl_info_free(struct decl_info *decl)
{
if (decl) {
for (size_t i = 0; i < decl->params.num; i++)
decl_param_free(decl->params.array+i);
da_free(decl->params);
bfree(decl->name);
memset(decl, 0, sizeof(struct decl_info));
}
}
EXPORT bool parse_decl_string(struct decl_info *decl, const char *decl_string);
#ifdef __cplusplus
}
#endif

View file

@ -16,17 +16,18 @@
#include "../util/darray.h"
#include "decl.h"
#include "proc.h"
struct proc_info {
char *name;
void *data;
proc_handler_proc_t proc;
struct decl_info func;
void *data;
proc_handler_proc_t callback;
};
static inline void proc_info_free(struct proc_info *pi)
{
bfree(pi->name);
decl_info_free(&pi->func);
}
struct proc_handler {
@ -51,12 +52,23 @@ void proc_handler_destroy(proc_handler_t handler)
}
}
void proc_handler_add(proc_handler_t handler, const char *name,
void proc_handler_add(proc_handler_t handler, const char *decl_string,
proc_handler_proc_t proc, void *data)
{
if (!handler) return;
struct proc_info pi = {bstrdup(name), data, proc};
struct proc_info pi;
memset(&pi, 0, sizeof(struct proc_info));
if (!parse_decl_string(&pi.func, decl_string)) {
blog(LOG_ERROR, "Dynamic function declaration invalid: %s",
decl_string);
return;
}
pi.callback = proc;
pi.data = data;
da_push_back(handler->procs, &pi);
}
@ -68,8 +80,8 @@ bool proc_handler_call(proc_handler_t handler, const char *name,
for (size_t i = 0; i < handler->procs.num; i++) {
struct proc_info *info = handler->procs.array+i;
if (strcmp(info->name, name) == 0) {
info->proc(info->data, params);
if (strcmp(info->func.name, name) == 0) {
info->callback(info->data, params);
return true;
}
}

View file

@ -39,7 +39,7 @@ typedef void (*proc_handler_proc_t)(void*, calldata_t);
EXPORT proc_handler_t proc_handler_create(void);
EXPORT void proc_handler_destroy(proc_handler_t handler);
EXPORT void proc_handler_add(proc_handler_t handler, const char *name,
EXPORT void proc_handler_add(proc_handler_t handler, const char *decl_string,
proc_handler_proc_t proc, void *data);
/**

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013 Hugh Bailey <obs.jim@gmail.com>
* Copyright (c) 2013-2014 Hugh Bailey <obs.jim@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -17,6 +17,7 @@
#include "../util/darray.h"
#include "../util/threading.h"
#include "decl.h"
#include "signal.h"
struct signal_callback {
@ -25,23 +26,25 @@ struct signal_callback {
};
struct signal_info {
char *name;
struct decl_info func;
DARRAY(struct signal_callback) callbacks;
pthread_mutex_t mutex;
struct signal_info *next;
};
static inline struct signal_info *signal_info_create(const char *name)
static inline struct signal_info *signal_info_create(struct decl_info *info)
{
struct signal_info *si = bmalloc(sizeof(struct signal_info));
si->name = bstrdup(name);
si->func = *info;
si->next = NULL;
da_init(si->callbacks);
if (pthread_mutex_init(&si->mutex, NULL) != 0) {
blog(LOG_ERROR, "Could not create signal!");
bfree(si->name);
blog(LOG_ERROR, "Could not create signal");
decl_info_free(&si->func);
bfree(si);
return NULL;
}
@ -53,7 +56,7 @@ static inline void signal_info_destroy(struct signal_info *si)
{
if (si) {
pthread_mutex_destroy(&si->mutex);
bfree(si->name);
decl_info_free(&si->func);
da_free(si->callbacks);
bfree(si);
}
@ -73,7 +76,6 @@ static inline size_t signal_get_callback_idx(struct signal_info *si,
}
struct signal_handler {
/* TODO: might be good to use hash table instead */
struct signal_info *first;
pthread_mutex_t mutex;
};
@ -85,7 +87,7 @@ static struct signal_info *getsignal(signal_handler_t handler,
signal = handler->first;
while (signal != NULL) {
if (strcmp(signal->name, name) == 0)
if (strcmp(signal->func.name, name) == 0)
break;
last = signal;
@ -128,6 +130,37 @@ void signal_handler_destroy(signal_handler_t handler)
}
}
bool signal_handler_add(signal_handler_t handler, const char *signal_decl)
{
struct decl_info func = {0};
struct signal_info *sig, *last;
bool success = true;
if (!parse_decl_string(&func, signal_decl)) {
blog(LOG_ERROR, "Signal declaration invalid: %s", signal_decl);
return false;
}
pthread_mutex_lock(&handler->mutex);
sig = getsignal(handler, func.name, &last);
if (sig) {
blog(LOG_WARNING, "Signal declaration '%s' exists", func.name);
decl_info_free(&func);
success = false;
} else {
sig = signal_info_create(&func);
if (!last)
handler->first = sig;
else
last->next = sig;
}
pthread_mutex_unlock(&handler->mutex);
return success;
}
void signal_handler_connect(signal_handler_t handler, const char *signal,
signal_callback_t callback, void *data)
{
@ -140,16 +173,8 @@ void signal_handler_connect(signal_handler_t handler, const char *signal,
pthread_mutex_lock(&handler->mutex);
sig = getsignal(handler, signal, &last);
if (!sig) {
sig = signal_info_create(signal);
if (!last)
handler->first = sig;
else
last->next = sig;
if (!sig)
return;
}
if (!sig)
return;
pthread_mutex_unlock(&handler->mutex);

View file

@ -38,6 +38,23 @@ typedef void (*signal_callback_t)(void*, calldata_t);
EXPORT signal_handler_t signal_handler_create(void);
EXPORT void signal_handler_destroy(signal_handler_t handler);
EXPORT bool signal_handler_add(signal_handler_t handler,
const char *signal_decl);
static inline bool signal_handler_add_array(signal_handler_t handler,
const char **signal_decls)
{
bool success = true;
if (!signal_decls)
return false;
while (*signal_decls)
if (!signal_handler_add(handler, *(signal_decls++)))
success = false;
return success;
}
EXPORT void signal_handler_connect(signal_handler_t handler, const char *signal,
signal_callback_t callback, void *data);
EXPORT void signal_handler_disconnect(signal_handler_t handler,

View file

@ -306,7 +306,7 @@ static int ep_parse_pass_command(struct effect_parser *ep, struct ep_pass *pass)
if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF;
if (cf_token_is(&ep->cfp, "compile")) {
cf_adderror(&ep->cfp, "compile keyword not necessary",
LEVEL_WARNING, NULL, NULL, NULL);
LEX_WARNING, NULL, NULL, NULL);
if (!cf_next_valid_token(&ep->cfp)) return PARSE_EOF;
}
@ -463,7 +463,7 @@ static inline int ep_check_for_keyword(struct effect_parser *ep,
if (new_val && *val)
cf_adderror(&ep->cfp, "'$1' keyword already specified",
LEVEL_WARNING, keyword, NULL, NULL);
LEX_WARNING, keyword, NULL, NULL);
*val = new_val;
return PARSE_CONTINUE;
@ -750,7 +750,7 @@ static inline int ep_parse_param_assign_float_array(struct effect_parser *ep,
/* -------------------------------------------- */
if (float_type[0] < '1' || float_type[0] > '4')
cf_adderror(&ep->cfp, "Invalid row count", LEVEL_ERROR,
cf_adderror(&ep->cfp, "Invalid row count", LEX_ERROR,
NULL, NULL, NULL);
float_count = float_type[0]-'0';
@ -758,7 +758,7 @@ static inline int ep_parse_param_assign_float_array(struct effect_parser *ep,
if (float_type[1] == 'x') {
if (float_type[2] < '1' || float_type[2] > '4')
cf_adderror(&ep->cfp, "Invalid column count",
LEVEL_ERROR, NULL, NULL, NULL);
LEX_ERROR, NULL, NULL, NULL);
float_count *= float_type[2]-'0';
}
@ -794,7 +794,7 @@ static int ep_parse_param_assignment_val(struct effect_parser *ep,
return ep_parse_param_assign_float_array(ep, param);
cf_adderror(&ep->cfp, "Invalid type '$1' used for assignment",
LEVEL_ERROR, param->type, NULL, NULL);
LEX_ERROR, param->type, NULL, NULL);
return PARSE_CONTINUE;
}
@ -877,7 +877,7 @@ static inline void report_invalid_func_keyword(struct effect_parser *ep,
{
if (val)
cf_adderror(&ep->cfp, "'$1' keyword cannot be used with a "
"function", LEVEL_ERROR,
"function", LEX_ERROR,
name, NULL, NULL);
}
@ -959,7 +959,7 @@ bool ep_parse(struct effect_parser *ep, effect_t effect,
} else if (cf_token_is(&ep->cfp, "{")) {
/* add error and pass braces */
cf_adderror(&ep->cfp, "Unexpected code segment",
LEVEL_ERROR, NULL, NULL, NULL);
LEX_ERROR, NULL, NULL, NULL);
cf_pass_pair(&ep->cfp, '{', '}');
} else {

View file

@ -312,7 +312,7 @@ static inline int sp_check_for_keyword(struct shader_parser *sp,
if (new_val && *val)
cf_adderror(&sp->cfp, "'$1' keyword already specified",
LEVEL_WARNING, keyword, NULL, NULL);
LEX_WARNING, keyword, NULL, NULL);
*val = new_val;
return PARSE_CONTINUE;
@ -504,7 +504,7 @@ static inline int sp_parse_param_assign_float_array(struct shader_parser *sp,
/* -------------------------------------------- */
if (float_type[0] < '1' || float_type[0] > '4')
cf_adderror(&sp->cfp, "Invalid row count", LEVEL_ERROR,
cf_adderror(&sp->cfp, "Invalid row count", LEX_ERROR,
NULL, NULL, NULL);
float_count = float_type[0]-'0';
@ -512,7 +512,7 @@ static inline int sp_parse_param_assign_float_array(struct shader_parser *sp,
if (float_type[1] == 'x') {
if (float_type[2] < '1' || float_type[2] > '4')
cf_adderror(&sp->cfp, "Invalid column count",
LEVEL_ERROR, NULL, NULL, NULL);
LEX_ERROR, NULL, NULL, NULL);
float_count *= float_type[2]-'0';
}
@ -546,7 +546,7 @@ static int sp_parse_param_assignment_val(struct shader_parser *sp,
return sp_parse_param_assign_float_array(sp, param);
cf_adderror(&sp->cfp, "Invalid type '$1' used for assignment",
LEVEL_ERROR, param->type, NULL, NULL);
LEX_ERROR, param->type, NULL, NULL);
return PARSE_CONTINUE;
}
@ -613,7 +613,7 @@ static inline void report_invalid_func_keyword(struct shader_parser *sp,
{
if (val)
cf_adderror(&sp->cfp, "'$1' keyword cannot be used with a "
"function", LEVEL_ERROR,
"function", LEX_ERROR,
name, NULL, NULL);
}
@ -668,7 +668,7 @@ bool shader_parse(struct shader_parser *sp, const char *shader,
} else if (cf_token_is(&sp->cfp, "{")) {
cf_adderror(&sp->cfp, "Unexpected code segment",
LEVEL_ERROR, NULL, NULL, NULL);
LEX_ERROR, NULL, NULL, NULL);
cf_pass_pair(&sp->cfp, '{', '}');
} else {

View file

@ -24,7 +24,7 @@ static inline void signal_item_remove(struct obs_scene_item *item)
calldata_setptr(&params, "scene", item->parent);
calldata_setptr(&params, "item", item);
signal_handler_signal(item->parent->source->signals, "item-remove",
signal_handler_signal(item->parent->source->signals, "item_remove",
&params);
calldata_free(&params);
}
@ -196,6 +196,14 @@ static const struct obs_source_info scene_info =
.enum_sources = scene_enum_sources
};
static const char *obs_scene_signals[] = {
"void item_add(ptr scene, ptr item)",
"void item_remove(ptr scene, ptr item)",
NULL
};
obs_scene_t obs_scene_create(const char *name)
{
struct obs_source *source = bzalloc(sizeof(struct obs_source));
@ -206,6 +214,8 @@ obs_scene_t obs_scene_create(const char *name)
return NULL;
}
signal_handler_add_array(source->signals, obs_scene_signals);
source->settings = obs_data_create();
scene = scene_create(source->settings, source);
source->data = scene;
@ -213,6 +223,8 @@ obs_scene_t obs_scene_create(const char *name)
assert(scene);
if (!scene) {
obs_data_release(source->settings);
proc_handler_destroy(source->procs);
signal_handler_destroy(source->signals);
bfree(source);
return NULL;
}
@ -289,8 +301,10 @@ void obs_scene_enum_items(obs_scene_t scene,
obs_sceneitem_addref(item);
if (!callback(scene, item, param))
if (!callback(scene, item, param)) {
obs_sceneitem_release(item);
break;
}
obs_sceneitem_release(item);
@ -341,7 +355,7 @@ obs_sceneitem_t obs_scene_add(obs_scene_t scene, obs_source_t source)
calldata_setptr(&params, "scene", scene);
calldata_setptr(&params, "item", item);
signal_handler_signal(scene->source->signals, "item-add", &params);
signal_handler_signal(scene->source->signals, "item_add", &params);
calldata_free(&params);
return item;
@ -360,6 +374,8 @@ void obs_sceneitem_addref(obs_sceneitem_t item)
{
if (item)
++item->ref;
blog(LOG_DEBUG, "addref %s, ref: %d", item->source->name, item->ref);
}
void obs_sceneitem_release(obs_sceneitem_t item)
@ -367,6 +383,8 @@ void obs_sceneitem_release(obs_sceneitem_t item)
if (!item)
return;
blog(LOG_DEBUG, "release %s, ref: %d", item->source->name, item->ref);
if (--item->ref == 0)
obs_sceneitem_destroy(item);
}

View file

@ -71,6 +71,18 @@ static const struct obs_source_info *get_source_info(enum obs_source_type type,
return find_source(list, id);
}
static const char *source_signals[] = {
"void destroy(ptr source)",
"void add(ptr source)",
"void remove(ptr source)",
"void activate(ptr source)",
"void deactivate(ptr source)",
"void show(ptr source)",
"void hide(ptr source)",
"void volume(ptr source, in out float volume)",
NULL
};
bool obs_source_init_handlers(struct obs_source *source)
{
source->signals = signal_handler_create();
@ -78,7 +90,10 @@ bool obs_source_init_handlers(struct obs_source *source)
return false;
source->procs = proc_handler_create();
return (source->procs != NULL);
if (!source->procs)
return false;
return signal_handler_add_array(source->signals, source_signals);
}
const char *obs_source_getdisplayname(enum obs_source_type type,
@ -162,7 +177,7 @@ obs_source_t obs_source_create(enum obs_source_type type, const char *id,
if (!obs_source_init(source, info))
goto fail;
obs_source_dosignal(source, "source-create", NULL);
obs_source_dosignal(source, "source_create", NULL);
return source;
fail:
@ -197,7 +212,7 @@ static void obs_source_destroy(struct obs_source *source)
if (!source)
return;
obs_source_dosignal(source, "source-destroy", "destroy");
obs_source_dosignal(source, "source_destroy", "destroy");
if (source->filter_parent)
obs_source_filter_remove(source->filter_parent, source);
@ -274,7 +289,7 @@ void obs_source_remove(obs_source_t source)
pthread_mutex_unlock(&data->sources_mutex);
obs_source_dosignal(source, "source-remove", "remove");
obs_source_dosignal(source, "source_remove", "remove");
obs_source_release(source);
}
@ -311,28 +326,28 @@ static void activate_source(obs_source_t source)
{
if (source->info.activate)
source->info.activate(source->data);
obs_source_dosignal(source, "source-activate", "activate");
obs_source_dosignal(source, "source_activate", "activate");
}
static void deactivate_source(obs_source_t source)
{
if (source->info.deactivate)
source->info.deactivate(source->data);
obs_source_dosignal(source, "source-deactivate", "deactivate");
obs_source_dosignal(source, "source_deactivate", "deactivate");
}
static void show_source(obs_source_t source)
{
if (source->info.show)
source->info.show(source->data);
obs_source_dosignal(source, "source-show", "show");
obs_source_dosignal(source, "source_show", "show");
}
static void hide_source(obs_source_t source)
{
if (source->info.hide)
source->info.hide(source->data);
obs_source_dosignal(source, "source-hide", "hide");
obs_source_dosignal(source, "source_hide", "hide");
}
static void activate_tree(obs_source_t parent, obs_source_t child, void *param)
@ -1277,9 +1292,9 @@ void obs_source_setvolume(obs_source_t source, float volume)
calldata_setfloat(&data, "volume", volume);
signal_handler_signal(source->signals, "volume", &data);
signal_handler_signal(obs->signals, "source-volume", &data);
signal_handler_signal(obs->signals, "source_volume", &data);
volume = calldata_float(&data, "volume");
volume = (float)calldata_float(&data, "volume");
calldata_free(&data);
source->user_volume = volume;

View file

@ -407,6 +407,23 @@ static void obs_free_data(void)
pthread_mutex_destroy(&data->encoders_mutex);
}
static const char *obs_signals[] = {
"void source_create(ptr source)",
"void source_destroy(ptr source)",
"void source_add(ptr source)",
"void source_remove(ptr source)",
"void source_activate(ptr source)",
"void source_deactivate(ptr source)",
"void source_show(ptr source)",
"void source_hide(ptr source)",
"void source_volume(ptr source, in out float volume)",
"void channel_change(int channel, in out ptr source, ptr prev_source)",
"void master_volume(in out float volume)",
NULL
};
static inline bool obs_init_handlers(void)
{
obs->signals = signal_handler_create();
@ -414,7 +431,10 @@ static inline bool obs_init_handlers(void)
return false;
obs->procs = proc_handler_create();
return (obs->procs != NULL);
if (!obs->procs)
return false;
return signal_handler_add_array(obs->signals, obs_signals);
}
static bool obs_init(void)
@ -682,7 +702,7 @@ bool obs_add_source(obs_source_t source)
pthread_mutex_unlock(&obs->data.sources_mutex);
calldata_setptr(&params, "source", source);
signal_handler_signal(obs->signals, "source-add", &params);
signal_handler_signal(obs->signals, "source_add", &params);
calldata_free(&params);
return true;
@ -709,10 +729,10 @@ void obs_set_output_source(uint32_t channel, obs_source_t source)
prev_source = view->channels[channel];
calldata_setuint32(&params, "channel", channel);
calldata_setint(&params, "channel", channel);
calldata_setptr(&params, "prev_source", prev_source);
calldata_setptr(&params, "source", source);
signal_handler_signal(obs->signals, "channel-change", &params);
signal_handler_signal(obs->signals, "channel_change", &params);
calldata_getptr(&params, "source", &source);
calldata_free(&params);
@ -854,8 +874,8 @@ void obs_set_master_volume(float volume)
if (!obs) return;
calldata_setfloat(&data, "volume", volume);
signal_handler_signal(obs->signals, "master-volume", &data);
volume = calldata_float(&data, "volume");
signal_handler_signal(obs->signals, "master_volume", &data);
volume = (float)calldata_float(&data, "volume");
calldata_free(&data);
obs->audio.user_volume = volume;

View file

@ -562,14 +562,14 @@ static inline void cf_adderror(struct cf_preprocessor *pp,
const struct cf_token *token, const char *error,
const char *val1, const char *val2, const char *val3)
{
cf_addew(pp, token, error, LEVEL_ERROR, val1, val2, val3);
cf_addew(pp, token, error, LEX_ERROR, val1, val2, val3);
}
static inline void cf_addwarning(struct cf_preprocessor *pp,
const struct cf_token *token, const char *warning,
const char *val1, const char *val2, const char *val3)
{
cf_addew(pp, token, warning, LEVEL_WARNING, val1, val2, val3);
cf_addew(pp, token, warning, LEX_WARNING, val1, val2, val3);
}
static inline void cf_adderror_expecting(struct cf_preprocessor *pp,

View file

@ -83,18 +83,18 @@ EXPORT void cf_adderror(struct cf_parser *parser, const char *error,
static inline void cf_adderror_expecting(struct cf_parser *p,
const char *expected)
{
cf_adderror(p, "Expected $1", LEVEL_ERROR, expected, NULL, NULL);
cf_adderror(p, "Expected '$1'", LEX_ERROR, expected, NULL, NULL);
}
static inline void cf_adderror_unexpected_eof(struct cf_parser *p)
{
cf_adderror(p, "Unexpected end of file", LEVEL_ERROR,
cf_adderror(p, "Unexpected EOF", LEX_ERROR,
NULL, NULL, NULL);
}
static inline void cf_adderror_syntax_error(struct cf_parser *p)
{
cf_adderror(p, "Syntax error", LEVEL_ERROR,
cf_adderror(p, "Syntax error", LEX_ERROR,
NULL, NULL, NULL);
}
@ -162,6 +162,21 @@ static inline bool cf_go_to_token_type(struct cf_parser *p,
return p->cur_token->type != CFTOKEN_NONE;
}
static inline int cf_token_should_be(struct cf_parser *p,
const char *str, const char *goto1, const char *goto2)
{
if (strref_cmp(&p->cur_token->str, str) == 0)
return PARSE_SUCCESS;
if (goto1) {
if (!cf_go_to_token(p, goto1, goto2))
return PARSE_EOF;
}
cf_adderror_expecting(p, str);
return PARSE_CONTINUE;
}
static inline int cf_next_token_should_be(struct cf_parser *p,
const char *str, const char *goto1, const char *goto2)
{
@ -172,8 +187,10 @@ static inline int cf_next_token_should_be(struct cf_parser *p,
return PARSE_SUCCESS;
}
if (goto1)
cf_go_to_token(p, goto1, goto2);
if (goto1) {
if (!cf_go_to_token(p, goto1, goto2))
return PARSE_EOF;
}
cf_adderror_expecting(p, str);
return PARSE_CONTINUE;

View file

@ -158,8 +158,8 @@ static inline void base_token_copy(struct base_token *dst,
/* ------------------------------------------------------------------------- */
#define LEVEL_ERROR 0
#define LEVEL_WARNING 1
#define LEX_ERROR 0
#define LEX_WARNING 1
struct error_item {
char *error;
@ -230,7 +230,7 @@ static inline bool error_data_has_errors(struct error_data *ed)
{
size_t i;
for (i = 0; i < ed->errors.num; i++)
if (ed->errors.array[i].level == LEVEL_ERROR)
if (ed->errors.array[i].level == LEX_ERROR)
return true;
return false;

View file

@ -56,11 +56,11 @@ void OBSBasic::OBSInit()
if (!ResetAudio())
throw "Failed to initialize audio";
signal_handler_connect(obs_signalhandler(), "source-add",
signal_handler_connect(obs_signalhandler(), "source_add",
OBSBasic::SourceAdded, this);
signal_handler_connect(obs_signalhandler(), "source-remove",
signal_handler_connect(obs_signalhandler(), "source_remove",
OBSBasic::SourceRemoved, this);
signal_handler_connect(obs_signalhandler(), "channel-change",
signal_handler_connect(obs_signalhandler(), "channel_change",
OBSBasic::ChannelChanged, this);
/* TODO: this is a test */
@ -103,13 +103,25 @@ void OBSBasic::UpdateSources(OBSScene scene)
[] (obs_scene_t scene, obs_sceneitem_t item, void *p)
{
OBSBasic *window = static_cast<OBSBasic*>(p);
window->AddSceneItem(item);
window->InsertSceneItem(item);
UNUSED_PARAMETER(scene);
return true;
}, this);
}
void OBSBasic::InsertSceneItem(obs_sceneitem_t item)
{
obs_source_t source = obs_sceneitem_getsource(item);
const char *name = obs_source_getname(source);
QListWidgetItem *listItem = new QListWidgetItem(QT_UTF8(name));
listItem->setData(Qt::UserRole,
QVariant::fromValue(OBSSceneItem(item)));
ui->sources->insertItem(0, listItem);
}
/* Qt callbacks for invokeMethod */
void OBSBasic::AddScene(OBSSource source)
@ -122,9 +134,9 @@ void OBSBasic::AddScene(OBSSource source)
ui->scenes->addItem(item);
signal_handler_t handler = obs_source_signalhandler(source);
signal_handler_connect(handler, "item-add",
signal_handler_connect(handler, "item_add",
OBSBasic::SceneItemAdded, this);
signal_handler_connect(handler, "item-remove",
signal_handler_connect(handler, "item_remove",
OBSBasic::SceneItemRemoved, this);
}
@ -147,15 +159,9 @@ void OBSBasic::AddSceneItem(OBSSceneItem item)
{
obs_scene_t scene = obs_sceneitem_getscene(item);
obs_source_t source = obs_sceneitem_getsource(item);
const char *name = obs_source_getname(source);
if (GetCurrentScene() == scene) {
QListWidgetItem *listItem = new QListWidgetItem(QT_UTF8(name));
listItem->setData(Qt::UserRole,
QVariant::fromValue(OBSSceneItem(item)));
ui->sources->insertItem(0, listItem);
}
if (GetCurrentScene() == scene)
InsertSceneItem(item);
sourceSceneRefs[source] = sourceSceneRefs[source] + 1;
}
@ -261,7 +267,7 @@ void OBSBasic::SourceRemoved(void *data, calldata_t params)
void OBSBasic::ChannelChanged(void *data, calldata_t params)
{
obs_source_t source = (obs_source_t)calldata_ptr(params, "source");
uint32_t channel = calldata_uint32(params, "channel");
uint32_t channel = (uint32_t)calldata_int(params, "channel");
if (channel == 0)
QMetaObject::invokeMethod(static_cast<OBSBasic*>(data),
@ -416,7 +422,6 @@ void OBSBasic::on_scenes_currentItemChanged(QListWidgetItem *current,
scene = current->data(Qt::UserRole).value<OBSScene>();
source = obs_scene_getsource(scene);
UpdateSources(scene);
}
/* TODO: allow transitions */

View file

@ -38,6 +38,7 @@ private:
OBSSceneItem GetCurrentSceneItem();
void UpdateSources(OBSScene scene);
void InsertSceneItem(obs_sceneitem_t item);
private slots:
void AddSceneItem(OBSSceneItem item);

View file

@ -20,6 +20,7 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\libobs\callback\calldata.h" />
<ClInclude Include="..\..\..\libobs\callback\decl.h" />
<ClInclude Include="..\..\..\libobs\callback\proc.h" />
<ClInclude Include="..\..\..\libobs\callback\signal.h" />
<ClInclude Include="..\..\..\libobs\graphics\axisang.h" />
@ -73,6 +74,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\libobs\callback\calldata.c" />
<ClCompile Include="..\..\..\libobs\callback\decl.c" />
<ClCompile Include="..\..\..\libobs\callback\proc.c" />
<ClCompile Include="..\..\..\libobs\callback\signal.c" />
<ClCompile Include="..\..\..\libobs\graphics\axisang.c" />

View file

@ -213,6 +213,9 @@
<ClInclude Include="..\..\..\libobs\media-io\video-frame.h">
<Filter>media-io\Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\libobs\callback\decl.h">
<Filter>callback\Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\libobs\obs-output.c">
@ -362,5 +365,8 @@
<ClCompile Include="..\..\..\libobs\util\threading-windows.c">
<Filter>util\Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\libobs\callback\decl.c">
<Filter>callback\Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>